Merge remote-tracking branches 'asoc/topic/4554', 'asoc/topic/ab8500', 'asoc/topic...
authorMark Brown <broonie@kernel.org>
Sun, 12 Apr 2015 18:48:51 +0000 (19:48 +0100)
committerMark Brown <broonie@kernel.org>
Sun, 12 Apr 2015 18:48:51 +0000 (19:48 +0100)
1350 files changed:
Documentation/CodeOfConflict [new file with mode: 0644]
Documentation/cgroups/unified-hierarchy.txt
Documentation/devicetree/bindings/arm/exynos/power_domain.txt
Documentation/devicetree/bindings/arm/sti.txt
Documentation/devicetree/bindings/i2c/i2c-imx.txt
Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
Documentation/devicetree/bindings/net/apm-xgene-enet.txt
Documentation/devicetree/bindings/net/dsa/dsa.txt
Documentation/devicetree/bindings/power/power_domain.txt
Documentation/devicetree/bindings/serial/8250.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/of-serial.txt [deleted file]
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
Documentation/devicetree/bindings/submitting-patches.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
Documentation/filesystems/dlmfs.txt
Documentation/filesystems/ocfs2.txt
Documentation/input/alps.txt
Documentation/input/event-codes.txt
Documentation/input/multi-touch-protocol.txt
Documentation/power/suspend-and-interrupts.txt
Documentation/sound/alsa/ControlNames.txt
MAINTAINERS
Makefile
arch/arc/include/asm/processor.h
arch/arc/include/asm/stacktrace.h [new file with mode: 0644]
arch/arc/kernel/process.c
arch/arc/kernel/signal.c
arch/arc/kernel/stacktrace.c
arch/arc/kernel/unaligned.c
arch/arc/mm/fault.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/dts/am335x-bone-common.dtsi
arch/arm/boot/dts/am335x-bone.dts
arch/arm/boot/dts/am335x-lxm.dts
arch/arm/boot/dts/am33xx-clocks.dtsi
arch/arm/boot/dts/am437x-idk-evm.dts
arch/arm/boot/dts/am43xx-clocks.dtsi
arch/arm/boot/dts/am57xx-beagle-x15.dts
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9261.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9n12.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/dm8168-evm.dts
arch/arm/boot/dts/dm816x.dtsi
arch/arm/boot/dts/dra7-evm.dts
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/dra72-evm.dts
arch/arm/boot/dts/dra7xx-clocks.dtsi
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4-cpu-thermal.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos4210-trats.dts
arch/arm/boot/dts/exynos4210-universal_c210.dts
arch/arm/boot/dts/exynos4210.dtsi
arch/arm/boot/dts/exynos4212.dtsi
arch/arm/boot/dts/exynos4412-odroid-common.dtsi
arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos4412-trats2.dts
arch/arm/boot/dts/exynos4412.dtsi
arch/arm/boot/dts/exynos4x12.dtsi
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5420-trip-points.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos5440-trip-points.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos5440.dtsi
arch/arm/boot/dts/imx6qdl-sabresd.dtsi
arch/arm/boot/dts/imx6sl-evk.dts
arch/arm/boot/dts/omap2.dtsi
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5-core-thermal.dtsi
arch/arm/boot/dts/omap5-gpu-thermal.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/omap54xx-clocks.dtsi
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/sama5d3.dtsi
arch/arm/boot/dts/sama5d4.dtsi
arch/arm/boot/dts/socfpga.dtsi
arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
arch/arm/boot/dts/sun4i-a10.dtsi
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/sama5_defconfig
arch/arm/configs/sunxi_defconfig
arch/arm/configs/vexpress_defconfig
arch/arm/crypto/aesbs-core.S_shipped
arch/arm/crypto/bsaes-armv7.pl
arch/arm/include/asm/kvm_mmu.h
arch/arm/include/debug/at91.S
arch/arm/kernel/setup.c
arch/arm/kvm/arm.c
arch/arm/kvm/mmu.c
arch/arm/kvm/trace.h
arch/arm/mach-asm9260/Kconfig
arch/arm/mach-at91/pm.c
arch/arm/mach-at91/pm.h
arch/arm/mach-at91/pm_slowclock.S
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-exynos/suspend.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-msm/board-halibut.c
arch/arm/mach-msm/board-qsd8x50.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-pxa/idp.c
arch/arm/mach-pxa/irq.c
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-socfpga/core.h
arch/arm/mach-socfpga/socfpga.c
arch/arm/mach-sti/board-dt.c
arch/arm/mach-sunxi/Kconfig
arch/arm/mm/cache-l2x0.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault.c
arch/arm/mm/pageattr.c
arch/arm/plat-omap/dmtimer.c
arch/arm64/boot/dts/apm/apm-storm.dtsi
arch/arm64/boot/dts/arm/foundation-v8.dts
arch/arm64/boot/dts/arm/juno-clocks.dtsi
arch/arm64/boot/dts/arm/juno.dts
arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
arch/arm64/crypto/Makefile
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cmpxchg.h
arch/arm64/include/asm/cpuidle.h
arch/arm64/include/asm/insn.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/percpu.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/proc-fns.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/tlb.h
arch/arm64/include/asm/tlbflush.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/efi.c
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/head.S
arch/arm64/kernel/insn.c
arch/arm64/kernel/process.c
arch/arm64/kernel/psci-call.S [new file with mode: 0644]
arch/arm64/kernel/psci.c
arch/arm64/kernel/signal32.c
arch/arm64/kernel/vdso/gettimeofday.S
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/init.c
arch/arm64/mm/pageattr.c
arch/c6x/include/asm/pgtable.h
arch/frv/include/asm/pgtable.h
arch/m32r/include/asm/pgtable-2level.h
arch/m68k/include/asm/pgtable_mm.h
arch/metag/include/asm/io.h
arch/metag/include/asm/pgtable-bits.h [new file with mode: 0644]
arch/metag/include/asm/pgtable.h
arch/metag/include/asm/processor.h
arch/microblaze/kernel/entry.S
arch/mips/kvm/tlb.c
arch/mips/kvm/trace.h
arch/mn10300/include/asm/pgtable.h
arch/nios2/include/asm/ptrace.h
arch/nios2/include/asm/ucontext.h [deleted file]
arch/nios2/include/uapi/asm/Kbuild
arch/nios2/include/uapi/asm/elf.h
arch/nios2/include/uapi/asm/ptrace.h
arch/nios2/include/uapi/asm/sigcontext.h
arch/nios2/kernel/signal.c
arch/nios2/mm/fault.c
arch/parisc/include/asm/pgalloc.h
arch/parisc/include/asm/pgtable.h
arch/parisc/kernel/syscall_table.S
arch/powerpc/include/asm/cputhreads.h
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/irq_work.h [new file with mode: 0644]
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/reg.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dbell.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/smp.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/smp.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/mobility.c
arch/s390/include/asm/elf.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/page.h
arch/s390/include/asm/pgtable.h
arch/s390/kernel/ftrace.c
arch/s390/kernel/jump_label.c
arch/s390/kernel/module.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/processor.c
arch/s390/kernel/swsusp_asm64.S
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c
arch/s390/pci/pci.c
arch/s390/pci/pci_mmio.c
arch/sparc/Kconfig
arch/sparc/include/asm/hypervisor.h
arch/sparc/include/asm/io_64.h
arch/sparc/include/asm/starfire.h
arch/sparc/kernel/entry.h
arch/sparc/kernel/hvapi.c
arch/sparc/kernel/hvcalls.S
arch/sparc/kernel/pcr.c
arch/sparc/kernel/perf_event.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/starfire.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/traps_64.c
arch/sparc/lib/memmove.S
arch/sparc/mm/init_64.c
arch/x86/Kconfig
arch/x86/boot/compressed/aslr.c
arch/x86/boot/compressed/misc.c
arch/x86/boot/compressed/misc.h
arch/x86/crypto/aesni-intel_glue.c
arch/x86/include/asm/fpu-internal.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/xsave.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/apic_numachip.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/kgdb.c
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/kprobes/opt.c
arch/x86/kernel/module.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/traps.c
arch/x86/kernel/xsave.c
arch/x86/kvm/emulate.c
arch/x86/kvm/i8259.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/lapic.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lguest/Kconfig
arch/x86/pci/acpi.c
arch/x86/pci/common.c
arch/x86/pci/intel_mid_pci.c
arch/x86/pci/irq.c
arch/x86/platform/intel-mid/intel-mid.c
arch/x86/vdso/vdso32/sigreturn.S
arch/x86/xen/enlighten.c
arch/x86/xen/p2m.c
block/blk-merge.c
block/blk-mq-tag.c
block/blk-mq.c
block/blk-settings.c
drivers/acpi/acpi_lpss.c
drivers/acpi/pci_irq.c
drivers/acpi/resource.c
drivers/acpi/video.c
drivers/android/binder.c
drivers/ata/libata-core.c
drivers/ata/sata_fsl.c
drivers/base/power/domain.c
drivers/base/power/wakeup.c
drivers/base/regmap/internal.h
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
drivers/block/nbd.c
drivers/block/nvme-core.c
drivers/block/zram/zram_drv.c
drivers/bluetooth/btusb.c
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm_ibmvtpm.c
drivers/char/tpm/tpm_ibmvtpm.h
drivers/char/virtio_console.c
drivers/clk/at91/pmc.c
drivers/clk/at91/pmc.h
drivers/clk/clk-divider.c
drivers/clk/clk.c
drivers/clk/qcom/gcc-msm8960.c
drivers/clk/qcom/lcc-ipq806x.c
drivers/clk/qcom/lcc-msm8960.c
drivers/clk/ti/fapll.c
drivers/clocksource/Kconfig
drivers/clocksource/mtk_timer.c
drivers/clocksource/pxa_timer.c
drivers/clocksource/time-efm32.c
drivers/clocksource/timer-sun5i.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/ppc-corenet-cpufreq.c
drivers/cpuidle/cpuidle-mvebu-v7.c
drivers/cpuidle/cpuidle.c
drivers/dma-buf/fence.c
drivers/dma-buf/reservation.c
drivers/dma/amba-pl08x.c
drivers/dma/at_hdmac.c
drivers/dma/at_hdmac_regs.h
drivers/dma/at_xdmac.c
drivers/dma/bcm2835-dma.c
drivers/dma/dma-jz4740.c
drivers/dma/dw/core.c
drivers/dma/dw/platform.c
drivers/dma/edma.c
drivers/dma/imx-sdma.c
drivers/dma/ioat/dma_v3.c
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/moxart-dma.c
drivers/dma/omap-dma.c
drivers/dma/qcom_bam_dma.c
drivers/dma/sh/shdmac.c
drivers/firmware/dmi_scan.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-syscon.c
drivers/gpio/gpio-tps65912.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-of.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_drm_connector.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_connector.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/i915_debugfs.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_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_fifo_underrun.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/imx/dw_hdmi-imx.c
drivers/gpu/drm/imx/imx-ldb.c
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/radeon/radeon_bios.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_kfd.c
drivers/gpu/drm/radeon/radeon_mn.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/vce_v2_0.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/ipu-v3/ipu-di.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-microsoft.c
drivers/hid/hid-saitek.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sony.c
drivers/hid/hid-tivo.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_wac.c
drivers/hwmon/ads7828.c
drivers/i2c/busses/i2c-designware-baytrail.c
drivers/i2c/i2c-core.c
drivers/ide/ide-tape.c
drivers/iio/accel/bma180.c
drivers/iio/accel/bmc150-accel.c
drivers/iio/accel/kxcjk-1013.c
drivers/iio/adc/Kconfig
drivers/iio/adc/at91_adc.c
drivers/iio/adc/mcp3422.c
drivers/iio/adc/qcom-spmi-iadc.c
drivers/iio/adc/ti_am335x_adc.c
drivers/iio/adc/vf610_adc.c
drivers/iio/common/ssp_sensors/ssp_dev.c
drivers/iio/dac/ad5686.c
drivers/iio/gyro/bmg160.c
drivers/iio/humidity/dht11.c
drivers/iio/humidity/si7020.c
drivers/iio/imu/adis16400_core.c
drivers/iio/imu/adis_trigger.c
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
drivers/iio/imu/kmx61.c
drivers/iio/industrialio-core.c
drivers/iio/industrialio-event.c
drivers/iio/light/Kconfig
drivers/iio/magnetometer/Kconfig
drivers/iio/proximity/sx9500.c
drivers/infiniband/core/umem.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/misc/mma8450.c
drivers/input/mouse/alps.c
drivers/input/mouse/cyapa_gen3.c
drivers/input/mouse/cyapa_gen5.c
drivers/input/mouse/focaltech.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/input/touchscreen/Kconfig
drivers/iommu/Kconfig
drivers/iommu/arm-smmu.c
drivers/iommu/exynos-iommu.c
drivers/iommu/intel-iommu.c
drivers/iommu/io-pgtable-arm.c
drivers/iommu/ipmmu-vmsa.c
drivers/iommu/omap-iommu.c
drivers/iommu/rockchip-iommu.c
drivers/irqchip/irq-armada-370-xp.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/isdn/icn/icn.c
drivers/lguest/Kconfig
drivers/md/dm-io.c
drivers/md/dm-snap.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid5.c
drivers/mfd/kempld-core.c
drivers/mfd/rtsx_usb.c
drivers/misc/mei/init.c
drivers/mmc/core/pwrseq_simple.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/ubi/eba.c
drivers/net/Kconfig
drivers/net/appletalk/Kconfig
drivers/net/bonding/bond_main.c
drivers/net/can/Kconfig
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/usb/gs_usb.c
drivers/net/can/usb/kvaser_usb.c
drivers/net/can/usb/peak_usb/pcan_ucan.h
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/dsa/bcm_sf2.h
drivers/net/ethernet/8390/axnet_cs.c
drivers/net/ethernet/8390/pcnet_cs.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/amd/pcnet32.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bcmsysport.h
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmgenet.h
drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/dec/tulip/tulip_core.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_nvm.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.h
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_selftest.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/qp.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/pasemi/pasemi_mac.c
drivers/net/ethernet/qlogic/netxen/netxen_nic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ethernet/smsc/smc91c92_cs.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smc91x.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_mdio.c
drivers/net/ethernet/wiznet/w5100.c
drivers/net/ethernet/wiznet/w5300.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/ipvlan/ipvlan.h
drivers/net/ipvlan/ipvlan_core.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/macvtap.c
drivers/net/phy/amd-xgbe-phy.c
drivers/net/phy/phy.c
drivers/net/team/team.c
drivers/net/usb/Kconfig
drivers/net/usb/asix_common.c
drivers/net/usb/asix_devices.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/cx82310_eth.c
drivers/net/usb/hso.c
drivers/net/usb/plusb.c
drivers/net/usb/r8152.c
drivers/net/usb/sr9800.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wan/cosa.c
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/brcm80211/brcmfmac/feature.c
drivers/net/wireless/brcm80211/brcmfmac/vendor.c
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netfront.c
drivers/of/Kconfig
drivers/of/address.c
drivers/of/base.c
drivers/of/irq.c
drivers/of/overlay.c
drivers/of/unittest.c
drivers/pci/host/pci-versatile.c
drivers/pci/host/pci-xgene.c
drivers/pci/pci-sysfs.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/rsrc_pci.c [deleted file]
drivers/phy/phy-armada375-usb2.c
drivers/phy/phy-core.c
drivers/phy/phy-exynos-dp-video.c
drivers/phy/phy-exynos-mipi-video.c
drivers/phy/phy-exynos4210-usb2.c
drivers/phy/phy-exynos4x12-usb2.c
drivers/phy/phy-exynos5-usbdrd.c
drivers/phy/phy-exynos5250-usb2.c
drivers/phy/phy-hix5hd2-sata.c
drivers/phy/phy-miphy28lp.c
drivers/phy/phy-miphy365x.c
drivers/phy/phy-omap-control.c
drivers/phy/phy-omap-usb2.c
drivers/phy/phy-rockchip-usb.c
drivers/phy/phy-ti-pipe3.c
drivers/phy/phy-twl4030-usb.c
drivers/phy/phy-xgene.c
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/pinctrl/sunxi/pinctrl-sunxi.h
drivers/powercap/intel_rapl.c
drivers/regulator/core.c
drivers/regulator/da9210-regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/rk808-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/rpmsg/virtio_rpmsg_bus.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-ds1685.c
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-s3c.c
drivers/s390/block/dcssblk.c
drivers/s390/block/scm_blk_cluster.c
drivers/scsi/ipr.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_discover.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/sh/pm_runtime.c
drivers/spi/spi-atmel.c
drivers/spi/spi-dw-mid.c
drivers/spi/spi-dw-pci.c
drivers/spi/spi-dw.c
drivers/spi/spi-img-spfi.c
drivers/spi/spi-pl022.c
drivers/spi/spi-qup.c
drivers/spi/spi-ti-qspi.c
drivers/spi/spi.c
drivers/staging/comedi/drivers/adv_pci1710.c
drivers/staging/comedi/drivers/comedi_isadma.c
drivers/staging/comedi/drivers/vmk80xx.c
drivers/staging/iio/Kconfig
drivers/staging/iio/adc/mxs-lradc.c
drivers/staging/iio/magnetometer/hmc5843_core.c
drivers/staging/iio/resolver/ad2s1200.c
drivers/staging/vt6655/device_main.c
drivers/staging/vt6655/rf.c
drivers/staging/vt6656/rf.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_device.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_io.c
drivers/thermal/int340x_thermal/int3400_thermal.c
drivers/thermal/int340x_thermal/int340x_thermal_zone.c
drivers/thermal/intel_powerclamp.c
drivers/thermal/rcar_thermal.c
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/thermal_core.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
drivers/tty/bfin_jtag_comm.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/of_serial.c
drivers/tty/serial/samsung.c
drivers/tty/serial/sprd_serial.c
drivers/tty/tty_io.c
drivers/tty/tty_ioctl.c
drivers/usb/chipidea/udc.c
drivers/usb/class/cdc-acm.c
drivers/usb/common/usb-otg-fsm.c
drivers/usb/core/devio.c
drivers/usb/dwc2/core_intr.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_loopback.c
drivers/usb/gadget/function/f_phonet.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/g_zero.h
drivers/usb/gadget/function/uvc_v4l2.c
drivers/usb/gadget/function/uvc_video.c
drivers/usb/gadget/legacy/g_ffs.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/legacy/tcm_usb_gadget.c
drivers/usb/gadget/legacy/zero.c
drivers/usb/host/ehci-atmel.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h
drivers/usb/isp1760/isp1760-core.c
drivers/usb/isp1760/isp1760-hcd.c
drivers/usb/isp1760/isp1760-udc.c
drivers/usb/musb/Kconfig
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/omap2430.c
drivers/usb/phy/phy-am335x-control.c
drivers/usb/renesas_usbhs/Kconfig
drivers/usb/serial/bus.c
drivers/usb/serial/ch341.c
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/generic.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/mxuport.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/usb-serial.c
drivers/usb/storage/unusual_uas.h
drivers/usb/storage/usb.c
drivers/vfio/pci/vfio_pci_intrs.c
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/video/fbdev/amba-clcd.c
drivers/video/fbdev/core/fbmon.c
drivers/video/fbdev/omap2/dss/display-sysfs.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/watchdog/at91sam9_wdt.c
drivers/watchdog/imgpdc_wdt.c
drivers/watchdog/mtk_wdt.c
drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/events/events_base.c
drivers/xen/preempt.c [new file with mode: 0644]
drivers/xen/privcmd.c
drivers/xen/xen-pciback/conf_space.c
drivers/xen/xen-pciback/conf_space.h
drivers/xen/xen-pciback/conf_space_header.c
drivers/xen/xen-scsiback.c
fs/affs/file.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ordered-data.c
fs/btrfs/qgroup.c
fs/btrfs/send.c
fs/btrfs/tests/inode-tests.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/xattr.c
fs/cifs/cifsencrypt.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/keystore.c
fs/ecryptfs/main.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/hfsplus/brec.c
fs/kernfs/file.c
fs/locks.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4session.h
fs/nfs/nfs4state.c
fs/nfs/proc.c
fs/nfs/write.c
fs/nfsd/blocklayout.c
fs/nfsd/blocklayoutxdr.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfscache.c
fs/nilfs2/btree.c
fs/nilfs2/segment.c
fs/notify/fanotify/fanotify.c
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_fs.h
fs/overlayfs/super.c
fs/proc/task_mmu.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_iops.c
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_qm.c
include/drm/drm_mm.h
include/drm/i915_pciids.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/dt-bindings/pinctrl/am33xx.h
include/dt-bindings/pinctrl/am43xx.h
include/kvm/arm_vgic.h
include/linux/clk.h
include/linux/cpuidle.h
include/linux/device-mapper.h
include/linux/fs.h
include/linux/hid-sensor-hub.h
include/linux/interrupt.h
include/linux/irqchip/arm-gic-v3.h
include/linux/irqdesc.h
include/linux/kasan.h
include/linux/lcm.h
include/linux/libata.h
include/linux/mfd/palmas.h
include/linux/mlx4/qp.h
include/linux/module.h
include/linux/moduleloader.h
include/linux/netdevice.h
include/linux/nfs_fs.h
include/linux/of_platform.h
include/linux/pinctrl/consumer.h
include/linux/regulator/driver.h
include/linux/rhashtable.h
include/linux/sched.h
include/linux/serial_core.h
include/linux/skbuff.h
include/linux/spi/spi.h
include/linux/sunrpc/debug.h
include/linux/thermal.h
include/linux/uio.h
include/linux/usb/serial.h
include/linux/usb/usbnet.h
include/linux/vmalloc.h
include/linux/workqueue.h
include/linux/writeback.h
include/net/caif/cfpkt.h
include/net/dst.h
include/net/ip.h
include/net/ip6_route.h
include/net/netfilter/nf_log.h
include/net/netfilter/nf_tables.h
include/net/sock.h
include/net/vxlan.h
include/soc/at91/at91sam9_ddrsdr.h
include/sound/pcm_params.h
include/sound/rt5670.h
include/sound/soc-dapm.h
include/sound/soc-dpcm.h
include/sound/soc.h
include/target/target_core_backend.h
include/trace/events/regmap.h
include/uapi/linux/input.h
include/uapi/linux/nfsd/export.h
include/uapi/linux/serial.h
include/uapi/linux/tc_act/Kbuild
include/uapi/linux/virtio_blk.h
include/uapi/linux/virtio_scsi.h
include/video/omapdss.h
include/xen/xen-ops.h
include/xen/xenbus.h
kernel/cpuset.c
kernel/events/core.c
kernel/irq/manage.c
kernel/irq/pm.c
kernel/livepatch/core.c
kernel/locking/lockdep.c
kernel/locking/rtmutex.c
kernel/module.c
kernel/printk/console_cmdline.h
kernel/printk/printk.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/sched/idle.c
kernel/sys.c
kernel/sysctl.c
kernel/time/tick-broadcast-hrtimer.c
kernel/trace/ftrace.c
kernel/workqueue.c
lib/Makefile
lib/iov_iter.c [new file with mode: 0644]
lib/lcm.c
lib/lz4/lz4_decompress.c
lib/nlattr.c
lib/rhashtable.c
lib/seq_buf.c
lib/test_rhashtable.c
mm/Makefile
mm/cma.c
mm/huge_memory.c
mm/hugetlb.c
mm/iov_iter.c [deleted file]
mm/kasan/kasan.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/nommu.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_isolation.c
mm/pagewalk.c
mm/rmap.c
mm/shmem.c
mm/slub.c
mm/vmalloc.c
net/9p/trans_virtio.c
net/bridge/br.c
net/bridge/br_if.c
net/caif/caif_socket.c
net/caif/cffrml.c
net/caif/cfpkt_skbuff.c
net/can/af_can.c
net/compat.c
net/core/dev.c
net/core/ethtool.c
net/core/fib_rules.c
net/core/gen_stats.c
net/core/net_namespace.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/decnet/dn_route.c
net/decnet/dn_rules.c
net/dsa/dsa.c
net/hsr/hsr_device.c
net/hsr/hsr_main.c
net/hsr/hsr_slave.c
net/ipv4/fib_frontend.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/ip_forward.c
net/ipv4/ip_fragment.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipmr.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/ping.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/xfrm4_output.c
net/ipv6/addrconf.c
net/ipv6/datagram.c
net/ipv6/fib6_rules.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/ping.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp_offload.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/irda/ircomm/ircomm_tty.c
net/irda/irnet/irnet_ppp.c
net/iucv/af_iucv.c
net/l2tp/l2tp_core.c
net/mac80211/agg-rx.c
net/mac80211/chan.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rx.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nf_log.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nfnetlink_cthelper.c
net/netfilter/nft_compat.c
net/netfilter/nft_hash.c
net/netfilter/xt_TPROXY.c
net/netfilter/xt_recent.c
net/netfilter/xt_socket.c
net/netlink/af_netlink.c
net/openvswitch/datapath.c
net/openvswitch/flow_netlink.c
net/openvswitch/vport.c
net/openvswitch/vport.h
net/packet/af_packet.c
net/rds/iw_rdma.c
net/rxrpc/ar-ack.c
net/rxrpc/ar-error.c
net/rxrpc/ar-recvmsg.c
net/sched/act_bpf.c
net/sched/cls_u32.c
net/sched/ematch.c
net/socket.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/debugfs.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/xprt_rdma.h
net/tipc/core.c
net/tipc/link.c
net/tipc/socket.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/reg.c
net/xfrm/xfrm_policy.c
scripts/gdb/linux/__init__.py [new file with mode: 0644]
security/selinux/selinuxfs.c
sound/core/control.c
sound/core/pcm_native.c
sound/drivers/opl3/opl3_midi.c
sound/firewire/amdtp.c
sound/firewire/bebob/bebob.c
sound/firewire/bebob/bebob_stream.c
sound/firewire/dice/dice-stream.c
sound/firewire/dice/dice.c
sound/firewire/fireworks/fireworks.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/iso-resources.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/oxfw/oxfw.c
sound/isa/msnd/msnd_pinnacle_mixer.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/atmel-pcm-pdc.c
sound/soc/atmel/atmel-pcm.c [deleted file]
sound/soc/atmel/atmel-pcm.h
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_ssc_dai.h
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/cirrus/Kconfig
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/adau1977.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4554.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs4265.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/da732x.c
sound/soc/codecs/es8328.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rt286.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5670.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/sn95031.h
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta350.c
sound/soc/codecs/tas2552.c
sound/soc/codecs/tas5086.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8804-i2c.c [new file with mode: 0644]
sound/soc/codecs/wm8804-spi.c [new file with mode: 0644]
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8804.h
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/davinci/Kconfig
sound/soc/davinci/Makefile
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-pcm.c [deleted file]
sound/soc/davinci/davinci-pcm.h [deleted file]
sound/soc/davinci/davinci-vcif.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-es8328.c
sound/soc/fsl/wm1133-ev1.c
sound/soc/generic/simple-card.c
sound/soc/intel/Makefile
sound/soc/intel/atom/Makefile [new file with mode: 0644]
sound/soc/intel/atom/sst-atom-controls.c [new file with mode: 0644]
sound/soc/intel/atom/sst-atom-controls.h [new file with mode: 0644]
sound/soc/intel/atom/sst-mfld-dsp.h [new file with mode: 0644]
sound/soc/intel/atom/sst-mfld-platform-compress.c [new file with mode: 0644]
sound/soc/intel/atom/sst-mfld-platform-pcm.c [new file with mode: 0644]
sound/soc/intel/atom/sst-mfld-platform.h [new file with mode: 0644]
sound/soc/intel/atom/sst/Makefile [new file with mode: 0644]
sound/soc/intel/atom/sst/sst.c [new file with mode: 0644]
sound/soc/intel/atom/sst/sst.h [new file with mode: 0644]
sound/soc/intel/atom/sst/sst_acpi.c [new file with mode: 0644]
sound/soc/intel/atom/sst/sst_drv_interface.c [new file with mode: 0644]
sound/soc/intel/atom/sst/sst_ipc.c [new file with mode: 0644]
sound/soc/intel/atom/sst/sst_loader.c [new file with mode: 0644]
sound/soc/intel/atom/sst/sst_pci.c [new file with mode: 0644]
sound/soc/intel/atom/sst/sst_pvt.c [new file with mode: 0644]
sound/soc/intel/atom/sst/sst_stream.c [new file with mode: 0644]
sound/soc/intel/baytrail/Makefile [new file with mode: 0644]
sound/soc/intel/baytrail/sst-baytrail-dsp.c [new file with mode: 0644]
sound/soc/intel/baytrail/sst-baytrail-ipc.c [new file with mode: 0644]
sound/soc/intel/baytrail/sst-baytrail-ipc.h [new file with mode: 0644]
sound/soc/intel/baytrail/sst-baytrail-pcm.c [new file with mode: 0644]
sound/soc/intel/boards/Makefile [new file with mode: 0644]
sound/soc/intel/boards/broadwell.c [new file with mode: 0644]
sound/soc/intel/boards/byt-max98090.c [new file with mode: 0644]
sound/soc/intel/boards/byt-rt5640.c [new file with mode: 0644]
sound/soc/intel/boards/bytcr_rt5640.c [new file with mode: 0644]
sound/soc/intel/boards/cht_bsw_rt5645.c [new file with mode: 0644]
sound/soc/intel/boards/cht_bsw_rt5672.c [new file with mode: 0644]
sound/soc/intel/boards/haswell.c [new file with mode: 0644]
sound/soc/intel/boards/mfld_machine.c [new file with mode: 0644]
sound/soc/intel/broadwell.c [deleted file]
sound/soc/intel/byt-max98090.c [deleted file]
sound/soc/intel/byt-rt5640.c [deleted file]
sound/soc/intel/bytcr_dpcm_rt5640.c [deleted file]
sound/soc/intel/cht_bsw_rt5645.c [deleted file]
sound/soc/intel/cht_bsw_rt5672.c [deleted file]
sound/soc/intel/common/Makefile [new file with mode: 0644]
sound/soc/intel/common/sst-acpi.c [new file with mode: 0644]
sound/soc/intel/common/sst-dsp-priv.h [new file with mode: 0644]
sound/soc/intel/common/sst-dsp.c [new file with mode: 0644]
sound/soc/intel/common/sst-dsp.h [new file with mode: 0644]
sound/soc/intel/common/sst-firmware.c [new file with mode: 0644]
sound/soc/intel/common/sst-ipc.c [new file with mode: 0644]
sound/soc/intel/common/sst-ipc.h [new file with mode: 0644]
sound/soc/intel/haswell.c [deleted file]
sound/soc/intel/haswell/Makefile [new file with mode: 0644]
sound/soc/intel/haswell/sst-haswell-dsp.c [new file with mode: 0644]
sound/soc/intel/haswell/sst-haswell-ipc.c [new file with mode: 0644]
sound/soc/intel/haswell/sst-haswell-ipc.h [new file with mode: 0644]
sound/soc/intel/haswell/sst-haswell-pcm.c [new file with mode: 0644]
sound/soc/intel/mfld_machine.c [deleted file]
sound/soc/intel/sst-acpi.c [deleted file]
sound/soc/intel/sst-atom-controls.c [deleted file]
sound/soc/intel/sst-atom-controls.h [deleted file]
sound/soc/intel/sst-baytrail-dsp.c [deleted file]
sound/soc/intel/sst-baytrail-ipc.c [deleted file]
sound/soc/intel/sst-baytrail-ipc.h [deleted file]
sound/soc/intel/sst-baytrail-pcm.c [deleted file]
sound/soc/intel/sst-dsp-priv.h [deleted file]
sound/soc/intel/sst-dsp.c [deleted file]
sound/soc/intel/sst-dsp.h [deleted file]
sound/soc/intel/sst-firmware.c [deleted file]
sound/soc/intel/sst-haswell-dsp.c [deleted file]
sound/soc/intel/sst-haswell-ipc.c [deleted file]
sound/soc/intel/sst-haswell-ipc.h [deleted file]
sound/soc/intel/sst-haswell-pcm.c [deleted file]
sound/soc/intel/sst-mfld-dsp.h [deleted file]
sound/soc/intel/sst-mfld-platform-compress.c [deleted file]
sound/soc/intel/sst-mfld-platform-pcm.c [deleted file]
sound/soc/intel/sst-mfld-platform.h [deleted file]
sound/soc/intel/sst/Makefile [deleted file]
sound/soc/intel/sst/sst.c [deleted file]
sound/soc/intel/sst/sst.h [deleted file]
sound/soc/intel/sst/sst_acpi.c [deleted file]
sound/soc/intel/sst/sst_drv_interface.c [deleted file]
sound/soc/intel/sst/sst_ipc.c [deleted file]
sound/soc/intel/sst/sst_loader.c [deleted file]
sound/soc/intel/sst/sst_pci.c [deleted file]
sound/soc/intel/sst/sst_pvt.c [deleted file]
sound/soc/intel/sst/sst_stream.c [deleted file]
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/omap/Kconfig
sound/soc/omap/ams-delta.c
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-hdmi-audio.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-twl4030.c
sound/soc/omap/rx51.c
sound/soc/pxa/hx4700.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/ttc-dkb.c
sound/soc/pxa/z2.c
sound/soc/samsung/Kconfig
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/littlemill.c
sound/soc/samsung/lowland.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/smartq_wm8987.c
sound/soc/samsung/speyside.c
sound/soc/samsung/tobermory.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_max98090.c
sound/soc/tegra/tegra_rt5640.c
sound/soc/tegra/tegra_rt5677.c
sound/soc/tegra/tegra_wm8903.c
sound/usb/line6/playback.c
sound/usb/quirks-table.h
tools/perf/bench/mem-memcpy.c
tools/perf/config/Makefile.arch
tools/perf/config/feature-checks/Makefile
tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c
tools/perf/util/annotate.c
tools/perf/util/cloexec.c
tools/perf/util/evlist.h
tools/perf/util/symbol-elf.c
tools/power/cpupower/Makefile
tools/testing/selftests/Makefile
tools/testing/selftests/exec/execveat.c
tools/thermal/tmon/.gitignore [new file with mode: 0644]
tools/thermal/tmon/Makefile
tools/thermal/tmon/tmon.8
tools/thermal/tmon/tmon.c
tools/thermal/tmon/tui.c
virt/kvm/arm/vgic-v2.c
virt/kvm/arm/vgic-v3.c
virt/kvm/arm/vgic.c
virt/kvm/kvm_main.c

diff --git a/Documentation/CodeOfConflict b/Documentation/CodeOfConflict
new file mode 100644 (file)
index 0000000..1684d0b
--- /dev/null
@@ -0,0 +1,27 @@
+Code of Conflict
+----------------
+
+The Linux kernel development effort is a very personal process compared
+to "traditional" ways of developing software.  Your code and ideas
+behind it will be carefully reviewed, often resulting in critique and
+criticism.  The review will almost always require improvements to the
+code before it can be included in the kernel.  Know that this happens
+because everyone involved wants to see the best possible solution for
+the overall success of Linux.  This development process has been proven
+to create the most robust operating system kernel ever, and we do not
+want to do anything to cause the quality of submission and eventual
+result to ever decrease.
+
+If however, anyone feels personally abused, threatened, or otherwise
+uncomfortable due to this process, that is not acceptable.  If so,
+please contact the Linux Foundation's Technical Advisory Board at
+<tab@lists.linux-foundation.org>, or the individual members, and they
+will work to resolve the issue to the best of their ability.  For more
+information on who is on the Technical Advisory Board and what their
+role is, please see:
+       http://www.linuxfoundation.org/programs/advisory-councils/tab
+
+As a reviewer of code, please strive to keep things civil and focused on
+the technical issues involved.  We are all humans, and frustrations can
+be high on both sides of the process.  Try to keep in mind the immortal
+words of Bill and Ted, "Be excellent to each other."
index 71daa35..eb102fb 100644 (file)
@@ -404,8 +404,8 @@ supported and the interface files "release_agent" and
   be understood as an underflow into the highest possible value, -2 or
   -10M etc. do not work, so it's not consistent.
 
-  memory.low, memory.high, and memory.max will use the string
-  "infinity" to indicate and set the highest possible value.
+  memory.low, memory.high, and memory.max will use the string "max" to
+  indicate and set the highest possible value.
 
 5. Planned Changes
 
index f4445e5..1e09703 100644 (file)
@@ -22,6 +22,8 @@ Optional Properties:
        - pclkN, clkN: Pairs of parent of input clock and input clock to the
                devices in this power domain. Maximum of 4 pairs (N = 0 to 3)
                are supported currently.
+- power-domains: phandle pointing to the parent power domain, for more details
+                see Documentation/devicetree/bindings/power/power_domain.txt
 
 Node of a device using power domains must have a power-domains property
 defined with a phandle to respective power domain.
index d70ec35..8d27f6b 100644 (file)
@@ -13,6 +13,10 @@ Boards with the ST STiH407 SoC shall have the following properties:
 Required root node property:
 compatible = "st,stih407";
 
+Boards with the ST STiH410 SoC shall have the following properties:
+Required root node property:
+compatible = "st,stih410";
+
 Boards with the ST STiH418 SoC shall have the following properties:
 Required root node property:
 compatible = "st,stih418";
index 52d37fd..ce4311d 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
   - "fsl,vf610-i2c" for I2C compatible with the one integrated on Vybrid vf610 SoC
 - reg : Should contain I2C/HS-I2C registers location and length
 - interrupts : Should contain I2C/HS-I2C interrupt
+- clocks : Should contain the I2C/HS-I2C clock specifier
 
 Optional properties:
 - clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
index 33df393..8db3238 100644 (file)
@@ -27,6 +27,8 @@ property is used.
 - amd,serdes-cdr-rate: CDR rate speed selection
 - amd,serdes-pq-skew: PQ (data sampling) skew
 - amd,serdes-tx-amp: TX amplitude boost
+- amd,serdes-dfe-tap-config: DFE taps available to run
+- amd,serdes-dfe-tap-enable: DFE taps to enable
 
 Example:
        xgbe_phy@e1240800 {
@@ -41,4 +43,6 @@ Example:
                amd,serdes-cdr-rate = <2>, <2>, <7>;
                amd,serdes-pq-skew = <10>, <10>, <30>;
                amd,serdes-tx-amp = <15>, <15>, <10>;
+               amd,serdes-dfe-tap-config = <3>, <3>, <1>;
+               amd,serdes-dfe-tap-enable = <0>, <0>, <127>;
        };
index cfcc527..6151999 100644 (file)
@@ -4,7 +4,10 @@ Ethernet nodes are defined to describe on-chip ethernet interfaces in
 APM X-Gene SoC.
 
 Required properties for all the ethernet interfaces:
-- compatible: Should be "apm,xgene-enet"
+- compatible: Should state binding information from the following list,
+  - "apm,xgene-enet":    RGMII based 1G interface
+  - "apm,xgene1-sgenet": SGMII based 1G interface
+  - "apm,xgene1-xgenet": XFI based 10G interface
 - reg: Address and length of the register set for the device. It contains the
   information of registers in the same order as described by reg-names
 - reg-names: Should contain the register set names
index e124847..f0b4cd7 100644 (file)
@@ -19,7 +19,9 @@ the parent DSA node. The maximum number of allowed child nodes is 4
 (DSA_MAX_SWITCHES).
 Each of these switch child nodes should have the following required properties:
 
-- reg                  : Describes the switch address on the MII bus
+- reg                  : Contains two fields. The first one describes the
+                         address on the MII bus. The second is the switch
+                         number that must be unique in cascaded configurations
 - #address-cells       : Must be 1
 - #size-cells          : Must be 0
 
index 98c1667..0f8ed37 100644 (file)
@@ -19,6 +19,16 @@ Required properties:
    providing multiple PM domains (e.g. power controllers), but can be any value
    as specified by device tree binding documentation of particular provider.
 
+Optional properties:
+ - power-domains : A phandle and PM domain specifier as defined by bindings of
+                   the power controller specified by phandle.
+   Some power domains might be powered from another power domain (or have
+   other hardware specific dependencies). For representing such dependency
+   a standard PM domain consumer binding is used. When provided, all domains
+   created by the given provider should be subdomains of the domain
+   specified by this binding. More details about power domain specifier are
+   available in the next section.
+
 Example:
 
        power: power-controller@12340000 {
@@ -30,6 +40,25 @@ Example:
 The node above defines a power controller that is a PM domain provider and
 expects one cell as its phandle argument.
 
+Example 2:
+
+       parent: power-controller@12340000 {
+               compatible = "foo,power-controller";
+               reg = <0x12340000 0x1000>;
+               #power-domain-cells = <1>;
+       };
+
+       child: power-controller@12340000 {
+               compatible = "foo,power-controller";
+               reg = <0x12341000 0x1000>;
+               power-domains = <&parent 0>;
+               #power-domain-cells = <1>;
+       };
+
+The nodes above define two power controllers: 'parent' and 'child'.
+Domains created by the 'child' power controller are subdomains of '0' power
+domain provided by the 'parent' power controller.
+
 ==PM domain consumers==
 
 Required properties:
diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt
new file mode 100644 (file)
index 0000000..91d5ab0
--- /dev/null
@@ -0,0 +1,66 @@
+* UART (Universal Asynchronous Receiver/Transmitter)
+
+Required properties:
+- compatible : one of:
+       - "ns8250"
+       - "ns16450"
+       - "ns16550a"
+       - "ns16550"
+       - "ns16750"
+       - "ns16850"
+       - For Tegra20, must contain "nvidia,tegra20-uart"
+       - For other Tegra, must contain '"nvidia,<chip>-uart",
+         "nvidia,tegra20-uart"' where <chip> is tegra30, tegra114, tegra124,
+         tegra132, or tegra210.
+       - "nxp,lpc3220-uart"
+       - "ralink,rt2880-uart"
+       - "ibm,qpace-nwp-serial"
+       - "altr,16550-FIFO32"
+       - "altr,16550-FIFO64"
+       - "altr,16550-FIFO128"
+       - "fsl,16550-FIFO64"
+       - "fsl,ns16550"
+       - "serial" if the port type is unknown.
+- reg : offset and length of the register set for the device.
+- interrupts : should contain uart interrupt.
+- clock-frequency : the input clock frequency for the UART
+        or
+  clocks phandle to refer to the clk used as per Documentation/devicetree
+  /bindings/clock/clock-bindings.txt
+
+Optional properties:
+- current-speed : the current active speed of the UART.
+- reg-offset : offset to apply to the mapbase from the start of the registers.
+- reg-shift : quantity to shift the register offsets by.
+- reg-io-width : the size (in bytes) of the IO accesses that should be
+  performed on the device.  There are some systems that require 32-bit
+  accesses to the UART (e.g. TI davinci).
+- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
+  RTAS and should not be registered.
+- no-loopback-test: set to indicate that the port does not implements loopback
+  test mode
+- fifo-size: the fifo size of the UART.
+- auto-flow-control: one way to enable automatic flow control support. The
+  driver is allowed to detect support for the capability even without this
+  property.
+
+Note:
+* fsl,ns16550:
+  ------------
+  Freescale DUART is very similar to the PC16552D (and to a
+  pair of NS16550A), albeit with some nonstandard behavior such as
+  erratum A-004737 (relating to incorrect BRK handling).
+
+  Represents a single port that is compatible with the DUART found
+  on many Freescale chips (examples include mpc8349, mpc8548,
+  mpc8641d, p4080 and ls2085a).
+
+Example:
+
+       uart@80230000 {
+               compatible = "ns8250";
+               reg = <0x80230000 0x100>;
+               clock-frequency = <3686400>;
+               interrupts = <10>;
+               reg-shift = <2>;
+       };
diff --git a/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt b/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt
new file mode 100644 (file)
index 0000000..ebcbb62
--- /dev/null
@@ -0,0 +1,19 @@
+ETRAX FS UART
+
+Required properties:
+- compatible : "axis,etraxfs-uart"
+- reg: offset and length of the register set for the device.
+- interrupts: device interrupt
+
+Optional properties:
+- {dtr,dsr,ri,cd}-gpios: specify a GPIO for DTR/DSR/RI/CD
+  line respectively.
+
+Example:
+
+serial@b00260000 {
+       compatible = "axis,etraxfs-uart";
+       reg = <0xb0026000 0x1000>;
+       interrupts = <68>;
+       status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt
deleted file mode 100644 (file)
index 91d5ab0..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-* UART (Universal Asynchronous Receiver/Transmitter)
-
-Required properties:
-- compatible : one of:
-       - "ns8250"
-       - "ns16450"
-       - "ns16550a"
-       - "ns16550"
-       - "ns16750"
-       - "ns16850"
-       - For Tegra20, must contain "nvidia,tegra20-uart"
-       - For other Tegra, must contain '"nvidia,<chip>-uart",
-         "nvidia,tegra20-uart"' where <chip> is tegra30, tegra114, tegra124,
-         tegra132, or tegra210.
-       - "nxp,lpc3220-uart"
-       - "ralink,rt2880-uart"
-       - "ibm,qpace-nwp-serial"
-       - "altr,16550-FIFO32"
-       - "altr,16550-FIFO64"
-       - "altr,16550-FIFO128"
-       - "fsl,16550-FIFO64"
-       - "fsl,ns16550"
-       - "serial" if the port type is unknown.
-- reg : offset and length of the register set for the device.
-- interrupts : should contain uart interrupt.
-- clock-frequency : the input clock frequency for the UART
-        or
-  clocks phandle to refer to the clk used as per Documentation/devicetree
-  /bindings/clock/clock-bindings.txt
-
-Optional properties:
-- current-speed : the current active speed of the UART.
-- reg-offset : offset to apply to the mapbase from the start of the registers.
-- reg-shift : quantity to shift the register offsets by.
-- reg-io-width : the size (in bytes) of the IO accesses that should be
-  performed on the device.  There are some systems that require 32-bit
-  accesses to the UART (e.g. TI davinci).
-- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
-  RTAS and should not be registered.
-- no-loopback-test: set to indicate that the port does not implements loopback
-  test mode
-- fifo-size: the fifo size of the UART.
-- auto-flow-control: one way to enable automatic flow control support. The
-  driver is allowed to detect support for the capability even without this
-  property.
-
-Note:
-* fsl,ns16550:
-  ------------
-  Freescale DUART is very similar to the PC16552D (and to a
-  pair of NS16550A), albeit with some nonstandard behavior such as
-  erratum A-004737 (relating to incorrect BRK handling).
-
-  Represents a single port that is compatible with the DUART found
-  on many Freescale chips (examples include mpc8349, mpc8548,
-  mpc8641d, p4080 and ls2085a).
-
-Example:
-
-       uart@80230000 {
-               compatible = "ns8250";
-               reg = <0x80230000 0x100>;
-               clock-frequency = <3686400>;
-               interrupts = <10>;
-               reg-shift = <2>;
-       };
index 7f76214..289c40e 100644 (file)
@@ -21,6 +21,18 @@ Optional properties:
 - reg-io-width : the size (in bytes) of the IO accesses that should be
   performed on the device.  If this property is not present then single byte
   accesses are used.
+- dcd-override : Override the DCD modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- dsr-override : Override the DTS modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- cts-override : Override the CTS modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- ri-override : Override the RI modem status signal. This signal will always be
+  reported as inactive instead of being obtained from the modem status register.
+  Define this if your serial port does not use this pin.
 
 Example:
 
@@ -31,6 +43,10 @@ Example:
                interrupts = <10>;
                reg-shift = <2>;
                reg-io-width = <4>;
+               dcd-override;
+               dsr-override;
+               cts-override;
+               ri-override;
        };
 
 Example with one clock:
index c949abc..c3495be 100644 (file)
@@ -18,6 +18,7 @@ Required properties:
   * Headphones
   * Speakers
   * Mic Jack
+  * Int Mic
 
 - nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
   connected to the CODEC.
index 56742bc..7d44eae 100644 (file)
@@ -12,6 +12,9 @@ I. For patch submitters
 
        devicetree@vger.kernel.org
 
+     and Cc: the DT maintainers. Use scripts/get_maintainer.pl to identify
+     all of the DT maintainers.
+
   3) The Documentation/ portion of the patch should come in the series before
      the code implementing the binding.
 
index 389ca13..fae26d0 100644 (file)
@@ -20,6 +20,7 @@ amlogic       Amlogic, Inc.
 ams    AMS AG
 amstaos        AMS-Taos Inc.
 apm    Applied Micro Circuits Corporation (APM)
+arasan Arasan Chip Systems
 arm    ARM Ltd.
 armadeus       ARMadeus Systems SARL
 asahi-kasei    Asahi Kasei Corp.
@@ -27,6 +28,7 @@ atmel Atmel Corporation
 auo    AU Optronics Corporation
 avago  Avago Technologies
 avic   Shanghai AVIC Optoelectronics Co., Ltd.
+axis   Axis Communications AB
 bosch  Bosch Sensortec GmbH
 brcm   Broadcom Corporation
 buffalo        Buffalo, Inc.
index f90e294..a4d8697 100644 (file)
@@ -26,6 +26,11 @@ Optional properties:
 - atmel,disable : Should be present if you want to disable the watchdog.
 - atmel,idle-halt : Should be present if you want to stop the watchdog when
        entering idle state.
+       CAUTION: This property should be used with care, it actually makes the
+       watchdog not counting when the CPU is in idle state, therefore the
+       watchdog reset time depends on mean CPU usage and will not reset at all
+       if the CPU stop working while it is in idle state, which is probably
+       not what you want.
 - atmel,dbg-halt : Should be present if you want to stop the watchdog when
        entering debug state.
 
index 1b528b2..fcf4d50 100644 (file)
@@ -5,8 +5,8 @@ system.
 
 dlmfs is built with OCFS2 as it requires most of its infrastructure.
 
-Project web page:    http://oss.oracle.com/projects/ocfs2
-Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
+Project web page:    http://ocfs2.wiki.kernel.org
+Tools web page:      https://github.com/markfasheh/ocfs2-tools
 OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
 All code copyright 2005 Oracle except when otherwise noted.
index 28f8c08..4c49e54 100644 (file)
@@ -8,8 +8,8 @@ also make it attractive for non-clustered use.
 You'll want to install the ocfs2-tools package in order to at least
 get "mount.ocfs2" and "ocfs2_hb_ctl".
 
-Project web page:    http://oss.oracle.com/projects/ocfs2
-Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
+Project web page:    http://ocfs2.wiki.kernel.org
+Tools git tree:      https://github.com/markfasheh/ocfs2-tools
 OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
 All code copyright 2005 Oracle except when otherwise noted.
index a63e5e0..92ae734 100644 (file)
@@ -114,6 +114,9 @@ ALPS Absolute Mode - Protocol Version 2
  byte 4:  0   y6   y5   y4   y3   y2   y1   y0
  byte 5:  0   z6   z5   z4   z3   z2   z1   z0
 
+Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for
+the DualPoint Stick.
+
 Dualpoint device -- interleaved packet format
 ---------------------------------------------
 
@@ -127,6 +130,11 @@ Dualpoint device -- interleaved packet format
  byte 7:    0   y6   y5   y4   y3   y2   y1   y0
  byte 8:    0   z6   z5   z4   z3   z2   z1   z0
 
+Devices which use the interleaving format normally send standard PS/2 mouse
+packets for the DualPoint Stick + ALPS Absolute Mode packets for the
+touchpad, switching to the interleaved packet format when both the stick and
+the touchpad are used at the same time.
+
 ALPS Absolute Mode - Protocol Version 3
 ---------------------------------------
 
index c587a96..9670561 100644 (file)
@@ -294,6 +294,12 @@ accordingly. This property does not affect kernel behavior.
 The kernel does not provide button emulation for such devices but treats
 them as any other INPUT_PROP_BUTTONPAD device.
 
+INPUT_PROP_ACCELEROMETER
+-------------------------
+Directional axes on this device (absolute and/or relative x, y, z) represent
+accelerometer data. All other axes retain their meaning. A device must not mix
+regular directional axes and accelerometer axes on the same event node.
+
 Guidelines:
 ==========
 The guidelines below ensure proper single-touch and multi-finger functionality.
index 7b4f59c..b85d000 100644 (file)
@@ -312,9 +312,12 @@ ABS_MT_TOOL_TYPE
 
 The type of approaching tool. A lot of kernel drivers cannot distinguish
 between different tool types, such as a finger or a pen. In such cases, the
-event should be omitted. The protocol currently supports MT_TOOL_FINGER and
-MT_TOOL_PEN [2]. For type B devices, this event is handled by input core;
-drivers should instead use input_mt_report_slot_state().
+event should be omitted. The protocol currently supports MT_TOOL_FINGER,
+MT_TOOL_PEN, and MT_TOOL_PALM [2]. For type B devices, this event is handled
+by input core; drivers should instead use input_mt_report_slot_state().
+A contact's ABS_MT_TOOL_TYPE may change over time while still touching the
+device, because the firmware may not be able to determine which tool is being
+used when it first appears.
 
 ABS_MT_BLOB_ID
 
index 2f9c5a5..8afb29a 100644 (file)
@@ -40,8 +40,10 @@ but also to IPIs and to some other special-purpose interrupts.
 
 The IRQF_NO_SUSPEND flag is used to indicate that to the IRQ subsystem when
 requesting a special-purpose interrupt.  It causes suspend_device_irqs() to
-leave the corresponding IRQ enabled so as to allow the interrupt to work all
-the time as expected.
+leave the corresponding IRQ enabled so as to allow the interrupt to work as
+expected during the suspend-resume cycle, but does not guarantee that the
+interrupt will wake the system from a suspended state -- for such cases it is
+necessary to use enable_irq_wake().
 
 Note that the IRQF_NO_SUSPEND flag affects the entire IRQ and not just one
 user of it.  Thus, if the IRQ is shared, all of the interrupt handlers installed
@@ -110,8 +112,9 @@ any special interrupt handling logic for it to work.
 IRQF_NO_SUSPEND and enable_irq_wake()
 -------------------------------------
 
-There are no valid reasons to use both enable_irq_wake() and the IRQF_NO_SUSPEND
-flag on the same IRQ.
+There are very few valid reasons to use both enable_irq_wake() and the
+IRQF_NO_SUSPEND flag on the same IRQ, and it is never valid to use both for the
+same device.
 
 First of all, if the IRQ is not shared, the rules for handling IRQF_NO_SUSPEND
 interrupts (interrupt handlers are invoked after suspend_device_irqs()) are
@@ -120,4 +123,13 @@ handlers are not invoked after suspend_device_irqs()).
 
 Second, both enable_irq_wake() and IRQF_NO_SUSPEND apply to entire IRQs and not
 to individual interrupt handlers, so sharing an IRQ between a system wakeup
-interrupt source and an IRQF_NO_SUSPEND interrupt source does not make sense.
+interrupt source and an IRQF_NO_SUSPEND interrupt source does not generally
+make sense.
+
+In rare cases an IRQ can be shared between a wakeup device driver and an
+IRQF_NO_SUSPEND user. In order for this to be safe, the wakeup device driver
+must be able to discern spurious IRQs from genuine wakeup events (signalling
+the latter to the core with pm_system_wakeup()), must use enable_irq_wake() to
+ensure that the IRQ will function as a wakeup source, and must request the IRQ
+with IRQF_COND_SUSPEND to tell the core that it meets these requirements. If
+these requirements are not met, it is not valid to use IRQF_COND_SUSPEND.
index 79a6127..3fc1cf5 100644 (file)
@@ -71,11 +71,11 @@ SOURCE:
   HDMI/DP      (either HDMI or DisplayPort)
 
 Exceptions (deprecated):
-  [Digital] Capture Source
-  [Digital] Capture Switch     (aka input gain switch)
-  [Digital] Capture Volume     (aka input gain volume)
-  [Digital] Playback Switch    (aka output gain switch)
-  [Digital] Playback Volume    (aka output gain volume)
+  [Analogue|Digital] Capture Source
+  [Analogue|Digital] Capture Switch    (aka input gain switch)
+  [Analogue|Digital] Capture Volume    (aka input gain volume)
+  [Analogue|Digital] Playback Switch   (aka output gain switch)
+  [Analogue|Digital] Playback Volume   (aka output gain volume)
   Tone Control - Switch
   Tone Control - Bass
   Tone Control - Treble
index ddc5a8c..3a3c461 100644 (file)
@@ -637,8 +637,7 @@ F:      drivers/gpu/drm/radeon/radeon_kfd.h
 F:      include/uapi/linux/kfd_ioctl.h
 
 AMD MICROCODE UPDATE SUPPORT
-M:     Andreas Herrmann <herrmann.der.user@googlemail.com>
-L:     amd64-microcode@amd64.org
+M:     Borislav Petkov <bp@alien8.de>
 S:     Maintained
 F:     arch/x86/kernel/cpu/microcode/amd*
 
@@ -1030,6 +1029,16 @@ F:       arch/arm/mach-mxs/
 F:     arch/arm/boot/dts/imx*
 F:     arch/arm/configs/imx*_defconfig
 
+ARM/FREESCALE VYBRID ARM ARCHITECTURE
+M:     Shawn Guo <shawn.guo@linaro.org>
+M:     Sascha Hauer <kernel@pengutronix.de>
+R:     Stefan Agner <stefan@agner.ch>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
+F:     arch/arm/mach-imx/*vf610*
+F:     arch/arm/boot/dts/vf*
+
 ARM/GLOMATION GESBC9312SX MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1176,7 +1185,7 @@ M:        Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-mvebu/
-F:     drivers/rtc/armada38x-rtc
+F:     drivers/rtc/rtc-armada38x.c
 
 ARM/Marvell Berlin SoC support
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@@ -1188,6 +1197,7 @@ ARM/Marvell Dove/MV78xx0/Orion SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+M:     Gregory Clement <gregory.clement@free-electrons.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-dove/
@@ -1351,6 +1361,7 @@ F:        drivers/i2c/busses/i2c-rk3x.c
 F:     drivers/*/*rockchip*
 F:     drivers/*/*/*rockchip*
 F:     sound/soc/rockchip/
+N:     rockchip
 
 ARM/SAMSUNG EXYNOS ARM ARCHITECTURES
 M:     Kukjin Kim <kgene@kernel.org>
@@ -1664,8 +1675,8 @@ F:        drivers/misc/eeprom/at24.c
 F:     include/linux/platform_data/at24.h
 
 ATA OVER ETHERNET (AOE) DRIVER
-M:     "Ed L. Cashin" <ecashin@coraid.com>
-W:     http://support.coraid.com/support/linux
+M:     "Ed L. Cashin" <ed.cashin@acm.org>
+W:     http://www.openaoe.org/
 S:     Supported
 F:     Documentation/aoe/
 F:     drivers/block/aoe/
@@ -1730,7 +1741,7 @@ S:        Maintained
 F:     drivers/net/ethernet/atheros/
 
 ATM
-M:     Chas Williams <chas@cmf.nrl.navy.mil>
+M:     Chas Williams <3chas3@gmail.com>
 L:     linux-atm-general@lists.sourceforge.net (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
 W:     http://linux-atm.sourceforge.net
@@ -1751,7 +1762,7 @@ S:        Supported
 F:     drivers/tty/serial/atmel_serial.c
 
 ATMEL Audio ALSA driver
-M:     Bo Shen <voice.shen@atmel.com>
+M:     Nicolas Ferre <nicolas.ferre@atmel.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/atmel
@@ -2065,7 +2076,7 @@ F:        include/net/bluetooth/
 BONDING DRIVER
 M:     Jay Vosburgh <j.vosburgh@gmail.com>
 M:     Veaceslav Falico <vfalico@gmail.com>
-M:     Andy Gospodarek <andy@greyhouse.net>
+M:     Andy Gospodarek <gospo@cumulusnetworks.com>
 L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
 S:     Supported
@@ -2107,7 +2118,6 @@ F:        drivers/net/ethernet/broadcom/bnx2x/
 
 BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
 M:     Christian Daudt <bcm@fixthebug.org>
-M:     Matt Porter <mporter@linaro.org>
 M:     Florian Fainelli <f.fainelli@gmail.com>
 L:     bcm-kernel-feedback-list@broadcom.com
 T:     git git://github.com/broadcom/mach-bcm
@@ -2369,8 +2379,9 @@ F:        arch/x86/include/asm/tce.h
 
 CAN NETWORK LAYER
 M:     Oliver Hartkopp <socketcan@hartkopp.net>
+M:     Marc Kleine-Budde <mkl@pengutronix.de>
 L:     linux-can@vger.kernel.org
-W:     http://gitorious.org/linux-can
+W:     https://github.com/linux-can
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
 S:     Maintained
@@ -2386,7 +2397,7 @@ CAN NETWORK DRIVERS
 M:     Wolfgang Grandegger <wg@grandegger.com>
 M:     Marc Kleine-Budde <mkl@pengutronix.de>
 L:     linux-can@vger.kernel.org
-W:     http://gitorious.org/linux-can
+W:     https://github.com/linux-can
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
 S:     Maintained
@@ -3241,6 +3252,13 @@ S:       Maintained
 F:     Documentation/hwmon/dme1737
 F:     drivers/hwmon/dme1737.c
 
+DMI/SMBIOS SUPPORT
+M:     Jean Delvare <jdelvare@suse.de>
+S:     Maintained
+F:     drivers/firmware/dmi-id.c
+F:     drivers/firmware/dmi_scan.c
+F:     include/linux/dmi.h
+
 DOCKING STATION DRIVER
 M:     Shaohua Li <shaohua.li@intel.com>
 L:     linux-acpi@vger.kernel.org
@@ -5076,7 +5094,7 @@ S:        Supported
 F:     drivers/platform/x86/intel_menlow.c
 
 INTEL IA32 MICROCODE UPDATE SUPPORT
-M:     Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+M:     Borislav Petkov <bp@alien8.de>
 S:     Maintained
 F:     arch/x86/kernel/cpu/microcode/core*
 F:     arch/x86/kernel/cpu/microcode/intel*
@@ -5117,22 +5135,21 @@ M:      Deepak Saxena <dsaxena@plexity.net>
 S:     Maintained
 F:     drivers/char/hw_random/ixp4xx-rng.c
 
-INTEL ETHERNET DRIVERS (e100/e1000/e1000e/fm10k/igb/igbvf/ixgb/ixgbe/ixgbevf/i40e/i40evf)
+INTEL ETHERNET DRIVERS
 M:     Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-M:     Jesse Brandeburg <jesse.brandeburg@intel.com>
-M:     Bruce Allan <bruce.w.allan@intel.com>
-M:     Carolyn Wyborny <carolyn.wyborny@intel.com>
-M:     Don Skidmore <donald.c.skidmore@intel.com>
-M:     Greg Rose <gregory.v.rose@intel.com>
-M:     Matthew Vick <matthew.vick@intel.com>
-M:     John Ronciak <john.ronciak@intel.com>
-M:     Mitch Williams <mitch.a.williams@intel.com>
-M:     Linux NICS <linux.nics@intel.com>
-L:     e1000-devel@lists.sourceforge.net
+R:     Jesse Brandeburg <jesse.brandeburg@intel.com>
+R:     Shannon Nelson <shannon.nelson@intel.com>
+R:     Carolyn Wyborny <carolyn.wyborny@intel.com>
+R:     Don Skidmore <donald.c.skidmore@intel.com>
+R:     Matthew Vick <matthew.vick@intel.com>
+R:     John Ronciak <john.ronciak@intel.com>
+R:     Mitch Williams <mitch.a.williams@intel.com>
+L:     intel-wired-lan@lists.osuosl.org
 W:     http://www.intel.com/support/feedback.htm
 W:     http://e1000.sourceforge.net/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next.git
+Q:     http://patchwork.ozlabs.org/project/intel-wired-lan/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git
 S:     Supported
 F:     Documentation/networking/e100.txt
 F:     Documentation/networking/e1000.txt
@@ -7213,8 +7230,7 @@ ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
 M:     Mark Fasheh <mfasheh@suse.com>
 M:     Joel Becker <jlbec@evilplan.org>
 L:     ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
-W:     http://oss.oracle.com/projects/ocfs2/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2.git
+W:     http://ocfs2.wiki.kernel.org
 S:     Supported
 F:     Documentation/filesystems/ocfs2.txt
 F:     Documentation/filesystems/dlmfs.txt
@@ -8481,6 +8497,14 @@ S:       Supported
 L:     netdev@vger.kernel.org
 F:     drivers/net/ethernet/samsung/sxgbe/
 
+SAMSUNG THERMAL DRIVER
+M:     Lukasz Majewski <l.majewski@samsung.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-samsung-soc@vger.kernel.org
+S:     Supported
+T:     https://github.com/lmajewski/linux-samsung-thermal.git
+F:     drivers/thermal/samsung/
+
 SAMSUNG USB2 PHY DRIVER
 M:     Kamil Debski <k.debski@samsung.com>
 L:     linux-kernel@vger.kernel.org
@@ -10189,6 +10213,13 @@ S:     Maintained
 F:     Documentation/usb/ohci.txt
 F:     drivers/usb/host/ohci*
 
+USB OTG FSM (Finite State Machine)
+M:     Peter Chen <Peter.Chen@freescale.com>
+T:     git git://github.com/hzpeterchen/linux-usb.git
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+F:     drivers/usb/common/usb-otg-fsm.c
+
 USB OVER IP DRIVER
 M:     Valentina Manea <valentina.manea.m@gmail.com>
 M:     Shuah Khan <shuah.kh@samsung.com>
index 9fab639..54430f9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 0
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc7
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
index 4e54729..52312cb 100644 (file)
@@ -47,9 +47,6 @@ struct thread_struct {
 /* Forward declaration, a strange C thing */
 struct task_struct;
 
-/* Return saved PC of a blocked thread  */
-unsigned long thread_saved_pc(struct task_struct *t);
-
 #define task_pt_regs(p) \
        ((struct pt_regs *)(THREAD_SIZE + (void *)task_stack_page(p)) - 1)
 
@@ -72,18 +69,21 @@ unsigned long thread_saved_pc(struct task_struct *t);
 #define release_segments(mm)        do { } while (0)
 
 #define KSTK_EIP(tsk)   (task_pt_regs(tsk)->ret)
+#define KSTK_ESP(tsk)   (task_pt_regs(tsk)->sp)
 
 /*
  * Where abouts of Task's sp, fp, blink when it was last seen in kernel mode.
  * Look in process.c for details of kernel stack layout
  */
-#define KSTK_ESP(tsk)   (tsk->thread.ksp)
+#define TSK_K_ESP(tsk)         (tsk->thread.ksp)
 
-#define KSTK_REG(tsk, off)     (*((unsigned int *)(KSTK_ESP(tsk) + \
+#define TSK_K_REG(tsk, off)    (*((unsigned int *)(TSK_K_ESP(tsk) + \
                                        sizeof(struct callee_regs) + off)))
 
-#define KSTK_BLINK(tsk) KSTK_REG(tsk, 4)
-#define KSTK_FP(tsk)    KSTK_REG(tsk, 0)
+#define TSK_K_BLINK(tsk)       TSK_K_REG(tsk, 4)
+#define TSK_K_FP(tsk)          TSK_K_REG(tsk, 0)
+
+#define thread_saved_pc(tsk)   TSK_K_BLINK(tsk)
 
 extern void start_thread(struct pt_regs * regs, unsigned long pc,
                         unsigned long usp);
diff --git a/arch/arc/include/asm/stacktrace.h b/arch/arc/include/asm/stacktrace.h
new file mode 100644 (file)
index 0000000..b29b606
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
+ * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_STACKTRACE_H
+#define __ASM_STACKTRACE_H
+
+#include <linux/sched.h>
+
+/**
+ * arc_unwind_core - Unwind the kernel mode stack for an execution context
+ * @tsk:               NULL for current task, specific task otherwise
+ * @regs:              pt_regs used to seed the unwinder {SP, FP, BLINK, PC}
+ *                     If NULL, use pt_regs of @tsk (if !NULL) otherwise
+ *                     use the current values of {SP, FP, BLINK, PC}
+ * @consumer_fn:       Callback invoked for each frame unwound
+ *                     Returns 0 to continue unwinding, -1 to stop
+ * @arg:               Arg to callback
+ *
+ * Returns the address of first function in stack
+ *
+ * Semantics:
+ *  - synchronous unwinding (e.g. dump_stack): @tsk  NULL, @regs  NULL
+ *  - Asynchronous unwinding of sleeping task: @tsk !NULL, @regs  NULL
+ *  - Asynchronous unwinding of intr/excp etc: @tsk !NULL, @regs !NULL
+ */
+notrace noinline unsigned int arc_unwind_core(
+       struct task_struct *tsk, struct pt_regs *regs,
+       int (*consumer_fn) (unsigned int, void *),
+       void *arg);
+
+#endif /* __ASM_STACKTRACE_H */
index fdd8971..98c00a2 100644 (file)
@@ -192,29 +192,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
        return 0;
 }
 
-/*
- * API: expected by schedular Code: If thread is sleeping where is that.
- * What is this good for? it will be always the scheduler or ret_from_fork.
- * So we hard code that anyways.
- */
-unsigned long thread_saved_pc(struct task_struct *t)
-{
-       struct pt_regs *regs = task_pt_regs(t);
-       unsigned long blink = 0;
-
-       /*
-        * If the thread being queried for in not itself calling this, then it
-        * implies it is not executing, which in turn implies it is sleeping,
-        * which in turn implies it got switched OUT by the schedular.
-        * In that case, it's kernel mode blink can reliably retrieved as per
-        * the picture above (right above pt_regs).
-        */
-       if (t != current && t->state != TASK_RUNNING)
-               blink = *((unsigned int *)regs - 1);
-
-       return blink;
-}
-
 int elf_check_arch(const struct elf32_hdr *x)
 {
        unsigned int eflags;
index 114234e..edda76f 100644 (file)
@@ -67,7 +67,7 @@ stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,
               sigset_t *set)
 {
        int err;
-       err = __copy_to_user(&(sf->uc.uc_mcontext.regs), regs,
+       err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), regs,
                             sizeof(sf->uc.uc_mcontext.regs.scratch));
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t));
 
@@ -83,7 +83,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
        if (!err)
                set_current_blocked(&set);
 
-       err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs),
+       err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs.scratch),
                                sizeof(sf->uc.uc_mcontext.regs.scratch));
 
        return err;
@@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn)
        /* Don't restart from sigreturn */
        syscall_wont_restart(regs);
 
+       /*
+        * Ensure that sigreturn always returns to user mode (in case the
+        * regs saved on user stack got fudged between save and sigreturn)
+        * Otherwise it is easy to panic the kernel with a custom
+        * signal handler and/or restorer which clobberes the status32/ret
+        * to return to a bogus location in kernel mode.
+        */
+       regs->status32 |= STATUS_U_MASK;
+
        return regs->r0;
 
 badframe:
@@ -229,8 +238,11 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
 
        /*
         * handler returns using sigreturn stub provided already by userpsace
+        * If not, nuke the process right away
         */
-       BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER));
+       if(!(ksig->ka.sa.sa_flags & SA_RESTORER))
+               return 1;
+
        regs->blink = (unsigned long)ksig->ka.sa.sa_restorer;
 
        /* User Stack for signal handler will be above the frame just carved */
@@ -296,12 +308,12 @@ static void
 handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 {
        sigset_t *oldset = sigmask_to_save();
-       int ret;
+       int failed;
 
        /* Set up the stack frame */
-       ret = setup_rt_frame(ksig, oldset, regs);
+       failed = setup_rt_frame(ksig, oldset, regs);
 
-       signal_setup_done(ret, ksig, 0);
+       signal_setup_done(failed, ksig, 0);
 }
 
 void do_signal(struct pt_regs *regs)
index 9ce47cf..92320d6 100644 (file)
@@ -43,6 +43,10 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                                   struct pt_regs *regs,
                                   struct unwind_frame_info *frame_info)
 {
+       /*
+        * synchronous unwinding (e.g. dump_stack)
+        *  - uses current values of SP and friends
+        */
        if (tsk == NULL && regs == NULL) {
                unsigned long fp, sp, blink, ret;
                frame_info->task = current;
@@ -61,12 +65,17 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                frame_info->regs.r63 = ret;
                frame_info->call_frame = 0;
        } else if (regs == NULL) {
+               /*
+                * Asynchronous unwinding of sleeping task
+                *  - Gets SP etc from task's pt_regs (saved bottom of kernel
+                *    mode stack of task)
+                */
 
                frame_info->task = tsk;
 
-               frame_info->regs.r27 = KSTK_FP(tsk);
-               frame_info->regs.r28 = KSTK_ESP(tsk);
-               frame_info->regs.r31 = KSTK_BLINK(tsk);
+               frame_info->regs.r27 = TSK_K_FP(tsk);
+               frame_info->regs.r28 = TSK_K_ESP(tsk);
+               frame_info->regs.r31 = TSK_K_BLINK(tsk);
                frame_info->regs.r63 = (unsigned int)__switch_to;
 
                /* In the prologue of __switch_to, first FP is saved on stack
@@ -83,6 +92,10 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                frame_info->call_frame = 0;
 
        } else {
+               /*
+                * Asynchronous unwinding of intr/exception
+                *  - Just uses the pt_regs passed
+                */
                frame_info->task = tsk;
 
                frame_info->regs.r27 = regs->fp;
@@ -95,7 +108,7 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
 
 #endif
 
-static noinline unsigned int
+notrace noinline unsigned int
 arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
                int (*consumer_fn) (unsigned int, void *), void *arg)
 {
index 7ff5b5c..74db59b 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/perf_event.h>
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
 #include <asm/disasm.h>
@@ -253,6 +254,7 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs,
                }
        }
 
+       perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address);
        return 0;
 
 fault:
index 563cb27..6a2e006 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
 #include <linux/kdebug.h>
+#include <linux/perf_event.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu.h>
 
@@ -139,13 +140,20 @@ good_area:
                        return;
        }
 
+       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+
        if (likely(!(fault & VM_FAULT_ERROR))) {
                if (flags & FAULT_FLAG_ALLOW_RETRY) {
                        /* To avoid updating stats twice for retry case */
-                       if (fault & VM_FAULT_MAJOR)
+                       if (fault & VM_FAULT_MAJOR) {
                                tsk->maj_flt++;
-                       else
+                               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+                                             regs, address);
+                       } else {
                                tsk->min_flt++;
+                               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+                                             regs, address);
+                       }
 
                        if (fault & VM_FAULT_RETRY) {
                                flags &= ~FAULT_FLAG_ALLOW_RETRY;
index 9f1f09a..cf4c0c9 100644 (file)
@@ -619,6 +619,7 @@ config ARCH_PXA
        select GENERIC_CLOCKEVENTS
        select GPIO_PXA
        select HAVE_IDE
+       select IRQ_DOMAIN
        select MULTI_IRQ_HANDLER
        select PLAT_PXA
        select SPARSE_IRQ
index 7f99cd6..eb7bb51 100644 (file)
@@ -150,6 +150,7 @@ machine-$(CONFIG_ARCH_BERLIN)               += berlin
 machine-$(CONFIG_ARCH_CLPS711X)                += clps711x
 machine-$(CONFIG_ARCH_CNS3XXX)         += cns3xxx
 machine-$(CONFIG_ARCH_DAVINCI)         += davinci
+machine-$(CONFIG_ARCH_DIGICOLOR)       += digicolor
 machine-$(CONFIG_ARCH_DOVE)            += dove
 machine-$(CONFIG_ARCH_EBSA110)         += ebsa110
 machine-$(CONFIG_ARCH_EFM32)           += efm32
index 6cc25ed..c3255e0 100644 (file)
 
 &usb0 {
        status = "okay";
+       dr_mode = "peripheral";
 };
 
 &usb1 {
        cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
        cd-inverted;
 };
+
+&aes {
+       status = "okay";
+};
+
+&sham {
+       status = "okay";
+};
index 83d40f7..6b84937 100644 (file)
 &mmc1 {
        vmmc-supply = <&ldo3_reg>;
 };
-
-&sham {
-       status = "okay";
-};
-
-&aes {
-       status = "okay";
-};
index 7266a00..5c5667a 100644 (file)
        dual_emac_res_vlan = <3>;
 };
 
+&phy_sel {
+       rmii-clock-ext;
+};
+
 &mac {
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&cpsw_default>;
index 712edce..071b56a 100644 (file)
@@ -99,7 +99,7 @@
        ehrpwm0_tbclk: ehrpwm0_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <0>;
                reg = <0x0664>;
        };
        ehrpwm1_tbclk: ehrpwm1_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <1>;
                reg = <0x0664>;
        };
        ehrpwm2_tbclk: ehrpwm2_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <2>;
                reg = <0x0664>;
        };
index f9a17e2..0198f5a 100644 (file)
                >;
        };
 
-       i2c1_pins_default: i2c1_pins_default {
-               pinctrl-single,pins = <
-                       0x15c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_cs0.i2c1_scl */
-                       0x158 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_d1.i2c1_sda */
-               >;
-       };
-
-       i2c1_pins_sleep: i2c1_pins_sleep {
-               pinctrl-single,pins = <
-                       0x15c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_cs0.i2c1_scl */
-                       0x158 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_d1.i2c1_sda */
-               >;
-       };
-
        mmc1_pins_default: pinmux_mmc1_pins_default {
                pinctrl-single,pins = <
                        0x100 (PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
        status = "okay";
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&i2c0_pins_default>;
-       pinctrl-1 = <&i2c0_pins_default>;
+       pinctrl-1 = <&i2c0_pins_sleep>;
        clock-frequency = <400000>;
 
        at24@50 {
                pagesize = <64>;
                reg = <0x50>;
        };
-};
-
-&i2c1 {
-       status = "okay";
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&i2c1_pins_default>;
-       pinctrl-1 = <&i2c1_pins_default>;
-       clock-frequency = <400000>;
 
        tps: tps62362@60 {
                compatible = "ti,tps62362";
+               reg = <0x60>;
                regulator-name = "VDD_MPU";
                regulator-min-microvolt = <950000>;
                regulator-max-microvolt = <1330000>;
index c7dc9da..cfb4968 100644 (file)
        ehrpwm0_tbclk: ehrpwm0_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <0>;
                reg = <0x0664>;
        };
        ehrpwm1_tbclk: ehrpwm1_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <1>;
                reg = <0x0664>;
        };
        ehrpwm2_tbclk: ehrpwm2_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <2>;
                reg = <0x0664>;
        };
        ehrpwm3_tbclk: ehrpwm3_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <4>;
                reg = <0x0664>;
        };
        ehrpwm4_tbclk: ehrpwm4_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <5>;
                reg = <0x0664>;
        };
        ehrpwm5_tbclk: ehrpwm5_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <6>;
                reg = <0x0664>;
        };
index 03750af..6463f9e 100644 (file)
        pinctrl-0 = <&usb1_pins>;
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb2 {
        dr_mode = "peripheral";
 };
index fff0ee6..e7f0a4a 100644 (file)
 
                                        pinctrl_usart3_rts: usart3_rts-0 {
                                                atmel,pins =
-                                                       <AT91_PIOB 8 AT91_PERIPH_B AT91_PINCTRL_NONE>;  /* PC8 periph B */
+                                                       <AT91_PIOC 8 AT91_PERIPH_B AT91_PINCTRL_NONE>;
                                        };
 
                                        pinctrl_usart3_cts: usart3_cts-0 {
                                                atmel,pins =
-                                                       <AT91_PIOB 10 AT91_PERIPH_B AT91_PINCTRL_NONE>; /* PC10 periph B */
+                                                       <AT91_PIOC 10 AT91_PERIPH_B AT91_PINCTRL_NONE>;
                                        };
                                };
 
                        };
 
                        usb1: gadget@fffa4000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9260-udc";
                                reg = <0xfffa4000 0x4000>;
                                interrupts = <10 IRQ_TYPE_LEVEL_HIGH 2>;
                                clocks = <&udc_clk>, <&udpck>;
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index e247b0b..d55fdf2 100644 (file)
                        };
 
                        usb1: gadget@fffa4000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9261-udc";
                                reg = <0xfffa4000 0x4000>;
                                interrupts = <10 IRQ_TYPE_LEVEL_HIGH 2>;
-                               clocks = <&usb>, <&udc_clk>, <&udpck>;
-                               clock-names = "usb_clk", "udc_clk", "udpck";
+                               clocks = <&udc_clk>, <&udpck>;
+                               clock-names = "pclk", "hclk";
+                               atmel,matrix = <&matrix>;
                                status = "disabled";
                        };
 
                        };
 
                        matrix: matrix@ffffee00 {
-                               compatible = "atmel,at91sam9260-bus-matrix";
+                               compatible = "atmel,at91sam9260-bus-matrix", "syscon";
                                reg = <0xffffee00 0x200>;
                        };
 
index 1f67bb4..fce301c 100644 (file)
@@ -69,7 +69,7 @@
 
        sram1: sram@00500000 {
                compatible = "mmio-sram";
-               reg = <0x00300000 0x4000>;
+               reg = <0x00500000 0x4000>;
        };
 
        ahb {
                        };
 
                        usb1: gadget@fff78000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9263-udc";
                                reg = <0xfff78000 0x4000>;
                                interrupts = <24 IRQ_TYPE_LEVEL_HIGH 2>;
                                clocks = <&udc_clk>, <&udpck>;
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index ee80aa9..488af63 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00800000 0x100000>;
                        interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "hclk", "uhpck";
                        status = "disabled";
                };
index c2666a7..0c53a37 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index 818dabd..d221179 100644 (file)
                                reg = <0x00500000 0x80000
                                       0xf803c000 0x400>;
                                interrupts = <23 IRQ_TYPE_LEVEL_HIGH 0>;
-                               clocks = <&usb>, <&udphs_clk>;
+                               clocks = <&utmi>, <&udphs_clk>;
                                clock-names = "hclk", "pclk";
                                status = "disabled";
 
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00700000 0x100000>;
                        interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
index 857d028..afe678f 100644 (file)
                        DM816X_IOPAD(0x0aac, PIN_INPUT | MUX_MODE0)     /* SPI_D1 */
                >;
        };
+
+       mmc_pins: pinmux_mmc_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0a70, MUX_MODE0)                 /* SD_POW */
+                       DM816X_IOPAD(0x0a74, MUX_MODE0)                 /* SD_CLK */
+                       DM816X_IOPAD(0x0a78, MUX_MODE0)                 /* SD_CMD */
+                       DM816X_IOPAD(0x0a7C, MUX_MODE0)                 /* SD_DAT0 */
+                       DM816X_IOPAD(0x0a80, MUX_MODE0)                 /* SD_DAT1 */
+                       DM816X_IOPAD(0x0a84, MUX_MODE0)                 /* SD_DAT2 */
+                       DM816X_IOPAD(0x0a88, MUX_MODE0)                 /* SD_DAT2 */
+                       DM816X_IOPAD(0x0a8c, MUX_MODE2)                 /* GP1[7] */
+                       DM816X_IOPAD(0x0a90, MUX_MODE2)                 /* GP1[8] */
+               >;
+       };
+
+       usb0_pins: pinmux_usb0_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0d00, MUX_MODE0)                 /* USB0_DRVVBUS */
+               >;
+       };
+
+       usb1_pins: pinmux_usb0_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0d04, MUX_MODE0)                 /* USB1_DRVVBUS */
+               >;
+       };
 };
 
 &i2c1 {
 };
 
 &mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc_pins>;
        vmmc-supply = <&vmmcsd_fixed>;
+       bus-width = <4>;
+       cd-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
+};
+
+/* At least dm8168-evm rev c won't support multipoint, later may */
+&usb0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb0_pins>;
+       mentor,multipoint = <0>;
+};
+
+&usb1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb1_pins>;
+       mentor,multipoint = <0>;
 };
index d98d0f7..f35715b 100644 (file)
 
                        /* Device Configuration Registers */
                        scm_conf: syscon@600 {
-                               compatible = "syscon";
+                               compatible = "syscon", "simple-bus";
                                reg = <0x600 0x110>;
                                #address-cells = <1>;
                                #size-cells = <1>;
+                               ranges = <0 0x600 0x110>;
+
+                               usb_phy0: usb-phy@20 {
+                                       compatible = "ti,dm8168-usb-phy";
+                                       reg = <0x20 0x8>;
+                                       reg-names = "phy";
+                                       clocks = <&main_fapll 6>;
+                                       clock-names = "refclk";
+                                       #phy-cells = <0>;
+                                       syscon = <&scm_conf>;
+                               };
+
+                               usb_phy1: usb-phy@28 {
+                                       compatible = "ti,dm8168-usb-phy";
+                                       reg = <0x28 0x8>;
+                                       reg-names = "phy";
+                                       clocks = <&main_fapll 6>;
+                                       clock-names = "refclk";
+                                       #phy-cells = <0>;
+                                       syscon = <&scm_conf>;
+                               };
                        };
 
                        scrm_clocks: clocks {
                };
 
                gpio1: gpio@48032000 {
-                       compatible = "ti,omap3-gpio";
+                       compatible = "ti,omap4-gpio";
                        ti,hwmods = "gpio1";
+                       ti,gpio-always-on;
                        reg = <0x48032000 0x1000>;
-                       interrupts = <97>;
+                       interrupts = <96>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                gpio2: gpio@4804c000 {
-                       compatible = "ti,omap3-gpio";
+                       compatible = "ti,omap4-gpio";
                        ti,hwmods = "gpio2";
+                       ti,gpio-always-on;
                        reg = <0x4804c000 0x1000>;
-                       interrupts = <99>;
+                       interrupts = <98>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                gpmc: gpmc@50000000 {
                                reg-names = "mc", "control";
                                interrupts = <18>;
                                interrupt-names = "mc";
-                               dr_mode = "otg";
+                               dr_mode = "host";
+                               interface-type = <0>;
+                               phys = <&usb_phy0>;
+                               phy-names = "usb2-phy";
                                mentor,multipoint = <1>;
                                mentor,num-eps = <16>;
                                mentor,ram-bits = <12>;
 
                        usb1: usb@47401800 {
                                compatible = "ti,musb-am33xx";
-                               status = "disabled";
                                reg = <0x47401c00 0x400
                                       0x47401800 0x200>;
                                reg-names = "mc", "control";
                                interrupts = <19>;
                                interrupt-names = "mc";
-                               dr_mode = "otg";
+                               dr_mode = "host";
+                               interface-type = <0>;
+                               phys = <&usb_phy1>;
+                               phy-names = "usb2-phy";
                                mentor,multipoint = <1>;
                                mentor,num-eps = <16>;
                                mentor,ram-bits = <12>;
index 746cddb..7563d7c 100644 (file)
 
        dcan1_pins_default: dcan1_pins_default {
                pinctrl-single,pins = <
-                       0x3d0   (PIN_OUTPUT | MUX_MODE0) /* dcan1_tx */
-                       0x3d4   (MUX_MODE15)            /* dcan1_rx.off */
-                       0x418   (PULL_DIS | MUX_MODE1) /* wakeup0.dcan1_rx */
+                       0x3d0   (PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
+                       0x418   (PULL_UP | MUX_MODE1) /* wakeup0.dcan1_rx */
                >;
        };
 
        dcan1_pins_sleep: dcan1_pins_sleep {
                pinctrl-single,pins = <
-                       0x3d0   (MUX_MODE15)    /* dcan1_tx.off */
-                       0x3d4   (MUX_MODE15)    /* dcan1_rx.off */
-                       0x418   (MUX_MODE15)    /* wakeup0.off */
+                       0x3d0   (MUX_MODE15 | PULL_UP)  /* dcan1_tx.off */
+                       0x418   (MUX_MODE15 | PULL_UP)  /* wakeup0.off */
                >;
        };
 };
        };
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb1 {
        dr_mode = "peripheral";
        pinctrl-names = "default";
index 5827fed..c4659a9 100644 (file)
                                     <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4ae10000 {
                                      <0x4A096800 0x40>; /* pll_ctrl */
                                reg-names = "phy_rx", "phy_tx", "pll_ctrl";
                                ctrl-module = <&omap_control_sata>;
-                               clocks = <&sys_clkin1>;
-                               clock-names = "sysclk";
+                               clocks = <&sys_clkin1>, <&sata_ref_clk>;
+                               clock-names = "sysclk", "refclk";
                                #phy-cells = <0>;
                        };
 
                                              "wkupclk", "refclk",
                                              "div-clk", "phy-div";
                                #phy-cells = <0>;
-                               ti,hwmods = "pcie1-phy";
                        };
 
                        pcie2_phy: pciephy@4a095000 {
                                              "wkupclk", "refclk",
                                              "div-clk", "phy-div";
                                #phy-cells = <0>;
-                               ti,hwmods = "pcie2-phy";
                                status = "disabled";
                        };
                };
index 4d87117..40ed539 100644 (file)
 
        dcan1_pins_default: dcan1_pins_default {
                pinctrl-single,pins = <
-                       0x3d0   (PIN_OUTPUT | MUX_MODE0) /* dcan1_tx */
-                       0x3d4   (MUX_MODE15)            /* dcan1_rx.off */
-                       0x418   (PULL_DIS | MUX_MODE1) /* wakeup0.dcan1_rx */
+                       0x3d0   (PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
+                       0x418   (PULL_UP | MUX_MODE1)   /* wakeup0.dcan1_rx */
                >;
        };
 
        dcan1_pins_sleep: dcan1_pins_sleep {
                pinctrl-single,pins = <
-                       0x3d0   (MUX_MODE15)    /* dcan1_tx.off */
-                       0x3d4   (MUX_MODE15)    /* dcan1_rx.off */
-                       0x418   (MUX_MODE15)    /* wakeup0.off */
+                       0x3d0   (MUX_MODE15 | PULL_UP)  /* dcan1_tx.off */
+                       0x418   (MUX_MODE15 | PULL_UP)  /* wakeup0.off */
                >;
        };
 
        phy-supply = <&ldo4_reg>;
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb1 {
        dr_mode = "peripheral";
        pinctrl-names = "default";
index 4bdcbd6..99b09a4 100644 (file)
                ti,invert-autoidle-bit;
        };
 
+       dpll_core_byp_mux: dpll_core_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x012c>;
+       };
+
        dpll_core_ck: dpll_core_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-core-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_core_byp_mux>;
                reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_dsp_byp_mux: dpll_dsp_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x0240>;
+       };
+
        dpll_dsp_ck: dpll_dsp_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_dsp_byp_mux>;
                reg = <0x0234>, <0x0238>, <0x0240>, <0x023c>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_iva_byp_mux: dpll_iva_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x01ac>;
+       };
+
        dpll_iva_ck: dpll_iva_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_iva_byp_mux>;
                reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_gpu_byp_mux: dpll_gpu_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x02e4>;
+       };
+
        dpll_gpu_ck: dpll_gpu_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_gpu_byp_mux>;
                reg = <0x02d8>, <0x02dc>, <0x02e4>, <0x02e0>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_ddr_byp_mux: dpll_ddr_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x021c>;
+       };
+
        dpll_ddr_ck: dpll_ddr_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_ddr_byp_mux>;
                reg = <0x0210>, <0x0214>, <0x021c>, <0x0218>;
        };
 
                ti,invert-autoidle-bit;
        };
 
+       dpll_gmac_byp_mux: dpll_gmac_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x02b4>;
+       };
+
        dpll_gmac_ck: dpll_gmac_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_gmac_byp_mux>;
                reg = <0x02a8>, <0x02ac>, <0x02b4>, <0x02b0>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_eve_byp_mux: dpll_eve_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x0290>;
+       };
+
        dpll_eve_ck: dpll_eve_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_eve_byp_mux>;
                reg = <0x0284>, <0x0288>, <0x0290>, <0x028c>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_per_byp_mux: dpll_per_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x014c>;
+       };
+
        dpll_per_ck: dpll_per_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_per_byp_mux>;
                reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_usb_byp_mux: dpll_usb_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x018c>;
+       };
+
        dpll_usb_ck: dpll_usb_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-j-type-clock";
-               clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_usb_byp_mux>;
                reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
        };
 
index 277b48b..ac6b0ae 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "skeleton.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 #include <dt-bindings/clock/exynos3250.h>
 
 / {
                        interrupts = <0 216 0>;
                        clocks = <&cmu CLK_TMU_APBIF>;
                        clock-names = "tmu_apbif";
+                       #include "exynos4412-tmu-sensor-conf.dtsi"
                        status = "disabled";
                };
 
diff --git a/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi b/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi
new file mode 100644 (file)
index 0000000..735cb2f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Device tree sources for Exynos4 thermal zone
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <dt-bindings/thermal/thermal.h>
+
+/ {
+thermal-zones {
+       cpu_thermal: cpu-thermal {
+               thermal-sensors = <&tmu 0>;
+               polling-delay-passive = <0>;
+               polling-delay = <0>;
+               trips {
+                       cpu_alert0: cpu-alert-0 {
+                               temperature = <70000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_alert1: cpu-alert-1 {
+                               temperature = <95000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_alert2: cpu-alert-2 {
+                               temperature = <110000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_crit0: cpu-crit-0 {
+                               temperature = <120000>; /* millicelsius */
+                               hysteresis = <0>; /* millicelsius */
+                               type = "critical";
+                       };
+               };
+               cooling-maps {
+                       map0 {
+                               trip = <&cpu_alert0>;
+                       };
+                       map1 {
+                               trip = <&cpu_alert1>;
+                       };
+               };
+       };
+};
+};
index 76173ca..77ea547 100644 (file)
@@ -38,6 +38,7 @@
                i2c5 = &i2c_5;
                i2c6 = &i2c_6;
                i2c7 = &i2c_7;
+               i2c8 = &i2c_8;
                csis0 = &csis_0;
                csis1 = &csis_1;
                fimc0 = &fimc_0;
                compatible = "samsung,exynos4210-pd";
                reg = <0x10023C20 0x20>;
                #power-domain-cells = <0>;
+               power-domains = <&pd_lcd0>;
        };
 
        pd_cam: cam-power-domain@10023C00 {
                status = "disabled";
        };
 
+       i2c_8: i2c@138E0000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "samsung,s3c2440-hdmiphy-i2c";
+               reg = <0x138E0000 0x100>;
+               interrupts = <0 93 0>;
+               clocks = <&clock CLK_I2C_HDMI>;
+               clock-names = "i2c";
+               status = "disabled";
+
+               hdmi_i2c_phy: hdmiphy@38 {
+                       compatible = "exynos4210-hdmiphy";
+                       reg = <0x38>;
+               };
+       };
+
        spi_0: spi@13920000 {
                compatible = "samsung,exynos4210-spi";
                reg = <0x13920000 0x100>;
                status = "disabled";
        };
 
+       tmu: tmu@100C0000 {
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       hdmi: hdmi@12D00000 {
+               compatible = "samsung,exynos4210-hdmi";
+               reg = <0x12D00000 0x70000>;
+               interrupts = <0 92 0>;
+               clock-names = "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy",
+                       "mout_hdmi";
+               clocks = <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>,
+                       <&clock CLK_SCLK_PIXEL>, <&clock CLK_SCLK_HDMIPHY>,
+                       <&clock CLK_MOUT_HDMI>;
+               phy = <&hdmi_i2c_phy>;
+               power-domains = <&pd_tv>;
+               samsung,syscon-phandle = <&pmu_system_controller>;
+               status = "disabled";
+       };
+
+       mixer: mixer@12C10000 {
+               compatible = "samsung,exynos4210-mixer";
+               interrupts = <0 91 0>;
+               reg = <0x12C10000 0x2100>, <0x12c00000 0x300>;
+               power-domains = <&pd_tv>;
+               status = "disabled";
+       };
+
        ppmu_dmc0: ppmu_dmc0@106a0000 {
                compatible = "samsung,exynos-ppmu";
                reg = <0x106a0000 0x2000>;
index 3d6652a..32c5fd8 100644 (file)
                status = "okay";
        };
 
+       tmu@100C0000 {
+               status = "okay";
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 2 2>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 4 4>;
+                              };
+                      };
+               };
+       };
+
        camera {
                pinctrl-names = "default";
                pinctrl-0 = <>;
index b57e6b8..d4f2b11 100644 (file)
                        assigned-clock-rates = <0>, <160000000>;
                };
        };
+
+       hdmi_en: voltage-regulator-hdmi-5v {
+               compatible = "regulator-fixed";
+               regulator-name = "HDMI_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpe0 1 0>;
+               enable-active-high;
+       };
+
+       hdmi_ddc: i2c-ddc {
+               compatible = "i2c-gpio";
+               gpios = <&gpe4 2 0 &gpe4 3 0>;
+               i2c-gpio,delay-us = <100>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pinctrl-0 = <&i2c_ddc_bus>;
+               pinctrl-names = "default";
+               status = "okay";
+       };
+
+       mixer@12C10000 {
+               status = "okay";
+       };
+
+       hdmi@12D00000 {
+               hpd-gpio = <&gpx3 7 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmi_hpd>;
+               hdmi-en-supply = <&hdmi_en>;
+               vdd-supply = <&ldo3_reg>;
+               vdd_osc-supply = <&ldo4_reg>;
+               vdd_pll-supply = <&ldo3_reg>;
+               ddc = <&hdmi_ddc>;
+               status = "okay";
+       };
+
+       i2c@138E0000 {
+               status = "okay";
+       };
+};
+
+&pinctrl_1 {
+       hdmi_hpd: hdmi-hpd {
+               samsung,pins = "gpx3-7";
+               samsung,pin-pud = <0>;
+       };
+};
+
+&pinctrl_0 {
+       i2c_ddc_bus: i2c-ddc-bus {
+               samsung,pins = "gpe4-2", "gpe4-3";
+               samsung,pin-function = <2>;
+               samsung,pin-pud = <3>;
+               samsung,pin-drv = <0>;
+       };
 };
 
 &mdma1 {
index 67c832c..be89f83 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "exynos4.dtsi"
 #include "exynos4210-pinctrl.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 
 / {
        compatible = "samsung,exynos4210", "samsung,exynos4";
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@900 {
+               cpu0: cpu@900 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0x900>;
+                       cooling-min-level = <4>;
+                       cooling-max-level = <2>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@901 {
                reg = <0x03860000 0x1000>;
        };
 
-       tmu@100C0000 {
+       tmu: tmu@100C0000 {
                compatible = "samsung,exynos4210-tmu";
                interrupt-parent = <&combiner>;
                reg = <0x100C0000 0x100>;
                interrupts = <2 4>;
                clocks = <&clock CLK_TMU_APBIF>;
                clock-names = "tmu_apbif";
+               samsung,tmu_gain = <15>;
+               samsung,tmu_reference_voltage = <7>;
                status = "disabled";
        };
 
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&tmu 0>;
+
+                       trips {
+                             cpu_alert0: cpu-alert-0 {
+                                     temperature = <85000>; /* millicelsius */
+                             };
+                             cpu_alert1: cpu-alert-1 {
+                                     temperature = <100000>; /* millicelsius */
+                             };
+                             cpu_alert2: cpu-alert-2 {
+                                     temperature = <110000>; /* millicelsius */
+                             };
+                       };
+               };
+       };
+
        g2d@12800000 {
                compatible = "samsung,s5pv210-g2d";
                reg = <0x12800000 0x1000>;
                };
        };
 
+       mixer: mixer@12C10000 {
+               clock-names = "mixer", "hdmi", "sclk_hdmi", "vp", "mout_mixer",
+                       "sclk_mixer";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                       <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>,
+                       <&clock CLK_MOUT_MIXER>, <&clock CLK_SCLK_MIXER>;
+       };
+
        ppmu_lcd1: ppmu_lcd1@12240000 {
                compatible = "samsung,exynos-ppmu";
                reg = <0x12240000 0x2000>;
index dd0a43e..5be0328 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@A00 {
+               cpu0: cpu@A00 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0xA00>;
+                       cooling-min-level = <13>;
+                       cooling-max-level = <7>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@A01 {
index de80b5b..adb4f6a 100644 (file)
                                        regulator-always-on;
                                };
 
+                               ldo8_reg: ldo@8 {
+                                       regulator-compatible = "LDO8";
+                                       regulator-name = "VDD10_HDMI_1.0V";
+                                       regulator-min-microvolt = <1000000>;
+                                       regulator-max-microvolt = <1000000>;
+                               };
+
+                               ldo10_reg: ldo@10 {
+                                       regulator-compatible = "LDO10";
+                                       regulator-name = "VDDQ_MIPIHSI_1.8V";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                               };
+
                                ldo11_reg: LDO11 {
                                        regulator-name = "VDD18_ABB1_1.8V";
                                        regulator-min-microvolt = <1800000>;
        ehci: ehci@12580000 {
                status = "okay";
        };
+
+       tmu@100C0000 {
+               vtmu-supply = <&ldo10_reg>;
+               status = "okay";
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 7 7>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 13 13>;
+                              };
+                      };
+               };
+       };
+
+       mixer: mixer@12C10000 {
+               status = "okay";
+       };
+
+       hdmi@12D00000 {
+               hpd-gpio = <&gpx3 7 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmi_hpd>;
+               vdd-supply = <&ldo8_reg>;
+               vdd_osc-supply = <&ldo10_reg>;
+               vdd_pll-supply = <&ldo8_reg>;
+               ddc = <&hdmi_ddc>;
+               status = "okay";
+       };
+
+       hdmi_ddc: i2c@13880000 {
+               status = "okay";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c2_bus>;
+       };
+
+       i2c@138E0000 {
+               status = "okay";
+       };
 };
 
 &pinctrl_1 {
                samsung,pin-pud = <0>;
                samsung,pin-drv = <0>;
        };
+
+       hdmi_hpd: hdmi-hpd {
+               samsung,pins = "gpx3-7";
+               samsung,pin-pud = <1>;
+       };
 };
diff --git a/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi
new file mode 100644 (file)
index 0000000..e3f7934
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Device tree sources for Exynos4412 TMU sensor configuration
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <dt-bindings/thermal/thermal_exynos.h>
+
+#thermal-sensor-cells = <0>;
+samsung,tmu_gain = <8>;
+samsung,tmu_reference_voltage = <16>;
+samsung,tmu_noise_cancel_mode = <4>;
+samsung,tmu_efuse_value = <55>;
+samsung,tmu_min_efuse_value = <40>;
+samsung,tmu_max_efuse_value = <100>;
+samsung,tmu_first_point_trim = <25>;
+samsung,tmu_second_point_trim = <85>;
+samsung,tmu_default_temp_offset = <50>;
+samsung,tmu_cal_type = <TYPE_ONE_POINT_TRIMMING>;
index 21f7480..173ffa4 100644 (file)
                pulldown-ohm = <100000>; /* 100K */
                io-channels = <&adc 2>;  /* Battery temperature */
        };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 7 7>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 13 13>;
+                              };
+                      };
+               };
+       };
 };
 
 &pmu_system_controller {
index 0f6ec93..68ad43b 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@A00 {
+               cpu0: cpu@A00 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0xA00>;
+                       cooling-min-level = <13>;
+                       cooling-max-level = <7>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@A01 {
index f5e0ae7..6a6abe1 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "exynos4.dtsi"
 #include "exynos4x12-pinctrl.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 
 / {
        aliases {
                clock-names = "tmu_apbif";
                status = "disabled";
        };
+
+       hdmi: hdmi@12D00000 {
+               compatible = "samsung,exynos4212-hdmi";
+       };
+
+       mixer: mixer@12C10000 {
+               compatible = "samsung,exynos4212-mixer";
+               clock-names = "mixer", "hdmi", "sclk_hdmi", "vp";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>;
+       };
 };
index 9bb1b0b..adbde1a 100644 (file)
@@ -20,7 +20,7 @@
 #include <dt-bindings/clock/exynos5250.h>
 #include "exynos5.dtsi"
 #include "exynos5250-pinctrl.dtsi"
-
+#include "exynos4-cpu-thermal.dtsi"
 #include <dt-bindings/clock/exynos-audss-clk.h>
 
 / {
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@0 {
+               cpu0: cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0>;
                        clock-frequency = <1700000000>;
+                       cooling-min-level = <15>;
+                       cooling-max-level = <9>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
                cpu@1 {
                        device_type = "cpu";
                #power-domain-cells = <0>;
        };
 
+       pd_disp1: disp1-power-domain@100440A0 {
+               compatible = "samsung,exynos4210-pd";
+               reg = <0x100440A0 0x20>;
+               #power-domain-cells = <0>;
+       };
+
        clock: clock-controller@10010000 {
                compatible = "samsung,exynos5250-clock";
                reg = <0x10010000 0x30000>;
                status = "disabled";
        };
 
-       tmu@10060000 {
+       tmu: tmu@10060000 {
                compatible = "samsung,exynos5250-tmu";
                reg = <0x10060000 0x100>;
                interrupts = <0 65 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&tmu 0>;
+
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 9 9>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 15 15>;
+                              };
+                      };
+               };
        };
 
        serial@12C00000 {
        hdmi: hdmi {
                compatible = "samsung,exynos4212-hdmi";
                reg = <0x14530000 0x70000>;
+               power-domains = <&pd_disp1>;
                interrupts = <0 95 0>;
                clocks = <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>,
                         <&clock CLK_SCLK_PIXEL>, <&clock CLK_SCLK_HDMIPHY>,
        mixer {
                compatible = "samsung,exynos5250-mixer";
                reg = <0x14450000 0x10000>;
+               power-domains = <&pd_disp1>;
                interrupts = <0 94 0>;
-               clocks = <&clock CLK_MIXER>, <&clock CLK_SCLK_HDMI>;
-               clock-names = "mixer", "sclk_hdmi";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>;
+               clock-names = "mixer", "hdmi", "sclk_hdmi";
        };
 
        dp_phy: video-phy@10040720 {
        };
 
        dp: dp-controller@145B0000 {
+               power-domains = <&pd_disp1>;
                clocks = <&clock CLK_DP>;
                clock-names = "dp";
                phys = <&dp_phy>;
        };
 
        fimd: fimd@14400000 {
+               power-domains = <&pd_disp1>;
                clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
                clock-names = "sclk_fimd", "fimd";
        };
diff --git a/arch/arm/boot/dts/exynos5420-trip-points.dtsi b/arch/arm/boot/dts/exynos5420-trip-points.dtsi
new file mode 100644 (file)
index 0000000..5d31fc1
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Device tree sources for default Exynos5420 thermal zone definition
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+polling-delay-passive = <0>;
+polling-delay = <0>;
+trips {
+       cpu-alert-0 {
+               temperature = <85000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-alert-1 {
+               temperature = <103000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-alert-2 {
+               temperature = <110000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-crit-0 {
+               temperature = <1200000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "critical";
+       };
+};
index 9dc2e97..c0e98cf 100644 (file)
                compatible = "samsung,exynos5420-mixer";
                reg = <0x14450000 0x10000>;
                interrupts = <0 94 0>;
-               clocks = <&clock CLK_MIXER>, <&clock CLK_SCLK_HDMI>;
-               clock-names = "mixer", "sclk_hdmi";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>;
+               clock-names = "mixer", "hdmi", "sclk_hdmi";
                power-domains = <&disp_pd>;
        };
 
                interrupts = <0 65 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu1: tmu@10064000 {
                interrupts = <0 183 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu2: tmu@10068000 {
                interrupts = <0 184 0>;
                clocks = <&clock CLK_TMU>, <&clock CLK_TMU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu3: tmu@1006c000 {
                interrupts = <0 185 0>;
                clocks = <&clock CLK_TMU>, <&clock CLK_TMU_GPU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_gpu: tmu@100a0000 {
                interrupts = <0 215 0>;
                clocks = <&clock CLK_TMU_GPU>, <&clock CLK_TMU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu0_thermal: cpu0-thermal {
+                       thermal-sensors = <&tmu_cpu0>;
+                       #include "exynos5420-trip-points.dtsi"
+               };
+               cpu1_thermal: cpu1-thermal {
+                      thermal-sensors = <&tmu_cpu1>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               cpu2_thermal: cpu2-thermal {
+                      thermal-sensors = <&tmu_cpu2>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               cpu3_thermal: cpu3-thermal {
+                      thermal-sensors = <&tmu_cpu3>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               gpu_thermal: gpu-thermal {
+                      thermal-sensors = <&tmu_gpu>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
        };
 
         watchdog: watchdog@101D0000 {
diff --git a/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi
new file mode 100644 (file)
index 0000000..7b2fba0
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Device tree sources for Exynos5440 TMU sensor configuration
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <dt-bindings/thermal/thermal_exynos.h>
+
+#thermal-sensor-cells = <0>;
+samsung,tmu_gain = <5>;
+samsung,tmu_reference_voltage = <16>;
+samsung,tmu_noise_cancel_mode = <4>;
+samsung,tmu_efuse_value = <0x5d2d>;
+samsung,tmu_min_efuse_value = <16>;
+samsung,tmu_max_efuse_value = <76>;
+samsung,tmu_first_point_trim = <25>;
+samsung,tmu_second_point_trim = <70>;
+samsung,tmu_default_temp_offset = <25>;
+samsung,tmu_cal_type = <TYPE_ONE_POINT_TRIMMING>;
diff --git a/arch/arm/boot/dts/exynos5440-trip-points.dtsi b/arch/arm/boot/dts/exynos5440-trip-points.dtsi
new file mode 100644 (file)
index 0000000..48adfa8
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Device tree sources for default Exynos5440 thermal zone definition
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+polling-delay-passive = <0>;
+polling-delay = <0>;
+trips {
+       cpu-alert-0 {
+               temperature = <100000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "active";
+       };
+       cpu-crit-0 {
+               temperature = <1050000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "critical";
+       };
+};
index 8f3373c..59d9416 100644 (file)
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
        };
 
        tmuctrl_1: tmuctrl@16011C {
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
        };
 
        tmuctrl_2: tmuctrl@160120 {
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu0_thermal: cpu0-thermal {
+                       thermal-sensors = <&tmuctrl_0>;
+                       #include "exynos5440-trip-points.dtsi"
+               };
+               cpu1_thermal: cpu1-thermal {
+                      thermal-sensors = <&tmuctrl_1>;
+                      #include "exynos5440-trip-points.dtsi"
+               };
+               cpu2_thermal: cpu2-thermal {
+                      thermal-sensors = <&tmuctrl_2>;
+                      #include "exynos5440-trip-points.dtsi"
+               };
        };
 
        sata@210000 {
index f1cd214..a626e6d 100644 (file)
@@ -35,6 +35,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio3 22 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_usb_h1_vbus: regulator@1 {
@@ -45,6 +46,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio1 29 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_audio: regulator@2 {
index fda4932..945887d 100644 (file)
@@ -52,6 +52,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio4 0 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_usb_otg2_vbus: regulator@1 {
@@ -62,6 +63,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio4 2 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_aud3v: regulator@2 {
index 59d1c29..578fa2a 100644 (file)
@@ -87,8 +87,8 @@
                                     <14>,
                                     <15>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <64>;
+                       dma-channels = <32>;
+                       dma-requests = <64>;
                };
 
                i2c1: i2c@48070000 {
index 6040327..db80f9d 100644 (file)
        model = "Nokia N900";
        compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3";
 
+       aliases {
+               i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+       };
+
        cpus {
                cpu@0 {
                        cpu0-supply = <&vcc>;
                compatible = "smsc,lan91c94";
                interrupt-parent = <&gpio2>;
                interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;  /* gpio54 */
-               reg = <1 0x300 0xf>;            /* 16 byte IO range at offset 0x300 */
+               reg = <1 0 0xf>;                /* 16 byte IO range */
                bank-width = <2>;
                pinctrl-names = "default";
                pinctrl-0 = <&ethernet_pins>;
index 01b7111..3fdc84f 100644 (file)
@@ -92,6 +92,8 @@
                        ti,hwmods = "aes";
                        reg = <0x480c5000 0x50>;
                        interrupts = <0>;
+                       dmas = <&sdma 65 &sdma 66>;
+                       dma-names = "tx", "rx";
                };
 
                prm: prm@48306000 {
                                     <14>,
                                     <15>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <96>;
+                       dma-channels = <32>;
+                       dma-requests = <96>;
                };
 
                omap3_pmx_core: pinmux@48002030 {
                        ti,hwmods = "sham";
                        reg = <0x480c3000 0x64>;
                        interrupts = <49>;
+                       dmas = <&sdma 69>;
+                       dma-names = "rx";
                };
 
                smartreflex_core: smartreflex@480cb000 {
index 074147c..87401d9 100644 (file)
                                     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4a310000 {
index 19212ac..de8a3d4 100644 (file)
@@ -13,7 +13,7 @@
 
 core_thermal: core_thermal {
        polling-delay-passive = <250>; /* milliseconds */
-       polling-delay = <1000>; /* milliseconds */
+       polling-delay = <500>; /* milliseconds */
 
                        /* sensor       ID */
        thermal-sensors = <&bandgap     2>;
index 1b87aca..bc3090f 100644 (file)
@@ -13,7 +13,7 @@
 
 gpu_thermal: gpu_thermal {
        polling-delay-passive = <250>; /* milliseconds */
-       polling-delay = <1000>; /* milliseconds */
+       polling-delay = <500>; /* milliseconds */
 
                        /* sensor       ID */
        thermal-sensors = <&bandgap     1>;
index b321fdf..4a485b6 100644 (file)
                                     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4ae10000 {
                                      <0x4A096800 0x40>; /* pll_ctrl */
                                reg-names = "phy_rx", "phy_tx", "pll_ctrl";
                                ctrl-module = <&omap_control_sata>;
-                               clocks = <&sys_clkin>;
-                               clock-names = "sysclk";
+                               clocks = <&sys_clkin>, <&sata_ref_clk>;
+                               clock-names = "sysclk", "refclk";
                                #phy-cells = <0>;
                        };
                };
        };
 };
 
+&cpu_thermal {
+       polling-delay = <500>; /* milliseconds */
+};
+
 /include/ "omap54xx-clocks.dtsi"
index 58c2746..83b425f 100644 (file)
                ti,index-starts-at-one;
        };
 
+       dpll_core_byp_mux: dpll_core_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x012c>;
+       };
+
        dpll_core_ck: dpll_core_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-core-clock";
-               clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin>, <&dpll_core_byp_mux>;
                reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_iva_byp_mux: dpll_iva_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x01ac>;
+       };
+
        dpll_iva_ck: dpll_iva_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_iva_byp_mux>;
                reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
        };
 
        };
 };
 &cm_core_clocks {
+
+       dpll_per_byp_mux: dpll_per_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x014c>;
+       };
+
        dpll_per_ck: dpll_per_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_per_byp_mux>;
                reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
        };
 
                ti,index-starts-at-one;
        };
 
+       dpll_usb_byp_mux: dpll_usb_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x018c>;
+       };
+
        dpll_usb_ck: dpll_usb_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-j-type-clock";
-               clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_usb_byp_mux>;
                reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
        };
 
index d771f68..eccc78d 100644 (file)
                        "mac_clk_rx", "mac_clk_tx",
                        "clk_mac_ref", "clk_mac_refout",
                        "aclk_mac", "pclk_mac";
+               status = "disabled";
        };
 
        usb_host0_ehci: usb@ff500000 {
index 261311b..367af53 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00700000 0x100000>;
                        interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
index d986b41..4303874 100644 (file)
@@ -66,6 +66,7 @@
                gpio4 = &pioE;
                tcb0 = &tcb0;
                tcb1 = &tcb1;
+               i2c0 = &i2c0;
                i2c2 = &i2c2;
        };
        cpus {
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00600000 0x100000>;
                        interrupts = <46 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
 
                                        lcdck: lcdck {
                                                #clock-cells = <0>;
-                                               reg = <4>;
-                                               clocks = <&smd>;
+                                               reg = <3>;
+                                               clocks = <&mck>;
                                        };
 
                                        smdck: smdck {
                                                reg = <50>;
                                        };
 
-                                       lcd_clk: lcd_clk {
+                                       lcdc_clk: lcdc_clk {
                                                #clock-cells = <0>;
                                                reg = <51>;
                                        };
index 252c3d1..d9176e6 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0xfff01000 0x1000>;
-                       interrupts = <0 156 4>;
+                       interrupts = <0 155 4>;
                        num-cs = <4>;
                        clocks = <&spi_m_clk>;
                        status = "disabled";
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&l4_sp_clk>;
+                       dmas = <&pdma 28>,
+                              <&pdma 29>;
+                       dma-names = "tx", "rx";
                };
 
                uart1: serial1@ffc03000 {
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&l4_sp_clk>;
+                       dmas = <&pdma 30>,
+                              <&pdma 31>;
+                       dma-names = "tx", "rx";
                };
 
                rst: rstmgr@ffd05000 {
index ab7891c..75742f8 100644 (file)
        model = "Olimex A10-OLinuXino-LIME";
        compatible = "olimex,a10-olinuxino-lime", "allwinner,sun4i-a10";
 
+       cpus {
+               cpu0: cpu@0 {
+                       /*
+                        * The A10-Lime is known to be unstable
+                        * when running at 1008 MHz
+                        */
+                       operating-points = <
+                               /* kHz    uV */
+                               912000  1350000
+                               864000  1300000
+                               624000  1250000
+                               >;
+                       cooling-max-level = <2>;
+               };
+       };
+
        soc@01c00000 {
                emac: ethernet@01c0b000 {
                        pinctrl-names = "default";
index 5c29258..eebb785 100644 (file)
@@ -75,7 +75,6 @@
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1056000 1500000
                                1008000 1400000
                                912000  1350000
                                864000  1300000
@@ -83,7 +82,7 @@
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <4>;
+                       cooling-max-level = <3>;
                };
        };
 
index f8818f1..883cb48 100644 (file)
@@ -47,7 +47,6 @@
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1104000 1500000
                                1008000 1400000
                                912000  1350000
                                864000  1300000
@@ -57,7 +56,7 @@
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <6>;
+                       cooling-max-level = <5>;
                };
        };
 
index 3a8530b..fdd1817 100644 (file)
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1008000 1450000
                                960000  1400000
                                912000  1400000
                                864000  1300000
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <7>;
+                       cooling-max-level = <6>;
                };
 
                cpu@1 {
index f2670f6..811e72b 100644 (file)
@@ -70,6 +70,7 @@ CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
+CONFIG_ARM_AT91_ETHER=y
 CONFIG_MACB=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
 CONFIG_DM9000=y
index e8a4c95..06075b6 100644 (file)
@@ -62,6 +62,17 @@ CONFIG_MACH_SPEAR1340=y
 CONFIG_ARCH_STI=y
 CONFIG_ARCH_EXYNOS=y
 CONFIG_EXYNOS5420_MCPM=y
+CONFIG_ARCH_SHMOBILE_MULTI=y
+CONFIG_ARCH_EMEV2=y
+CONFIG_ARCH_R7S72100=y
+CONFIG_ARCH_R8A73A4=y
+CONFIG_ARCH_R8A7740=y
+CONFIG_ARCH_R8A7779=y
+CONFIG_ARCH_R8A7790=y
+CONFIG_ARCH_R8A7791=y
+CONFIG_ARCH_R8A7794=y
+CONFIG_ARCH_SH73A0=y
+CONFIG_MACH_MARZEN=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_SIRF=y
 CONFIG_ARCH_TEGRA=y
@@ -84,9 +95,11 @@ CONFIG_PCI_KEYSTONE=y
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MVEBU=y
 CONFIG_PCI_TEGRA=y
+CONFIG_PCI_RCAR_GEN2=y
+CONFIG_PCI_RCAR_GEN2_PCIE=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_SMP=y
-CONFIG_NR_CPUS=8
+CONFIG_NR_CPUS=16
 CONFIG_HIGHPTE=y
 CONFIG_CMA=y
 CONFIG_ARM_APPENDED_DTB=y
@@ -130,6 +143,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_OMAP_OCP2SCP=y
+CONFIG_SIMPLE_PM_BUS=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -157,6 +171,7 @@ CONFIG_AHCI_SUNXI=y
 CONFIG_AHCI_TEGRA=y
 CONFIG_SATA_HIGHBANK=y
 CONFIG_SATA_MV=y
+CONFIG_SATA_RCAR=y
 CONFIG_NETDEVICES=y
 CONFIG_HIX5HD2_GMAC=y
 CONFIG_SUN4I_EMAC=y
@@ -167,14 +182,17 @@ CONFIG_MV643XX_ETH=y
 CONFIG_MVNETA=y
 CONFIG_KS8851=y
 CONFIG_R8169=y
+CONFIG_SH_ETH=y
 CONFIG_SMSC911X=y
 CONFIG_STMMAC_ETH=y
 CONFIG_TI_CPSW=y
 CONFIG_XILINX_EMACLITE=y
 CONFIG_AT803X_PHY=y
 CONFIG_MARVELL_PHY=y
+CONFIG_SMSC_PHY=y
 CONFIG_BROADCOM_PHY=y
 CONFIG_ICPLUS_PHY=y
+CONFIG_MICREL_PHY=y
 CONFIG_USB_PEGASUS=y
 CONFIG_USB_USBNET=y
 CONFIG_USB_NET_SMSC75XX=y
@@ -192,15 +210,18 @@ CONFIG_KEYBOARD_CROS_EC=y
 CONFIG_MOUSE_PS2_ELANTECH=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_ST1232=m
 CONFIG_TOUCHSCREEN_STMPE=y
 CONFIG_TOUCHSCREEN_SUN4I=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_MPU3050=y
 CONFIG_INPUT_AXP20X_PEK=y
+CONFIG_INPUT_ADXL34X=m
 CONFIG_SERIO_AMBAKMI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_EM=y
 CONFIG_SERIAL_8250_MT6577=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
@@ -213,6 +234,9 @@ CONFIG_SERIAL_SIRFSOC_CONSOLE=y
 CONFIG_SERIAL_TEGRA=y
 CONFIG_SERIAL_IMX=y
 CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=20
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_VT8500=y
@@ -233,19 +257,26 @@ CONFIG_I2C_MUX_PCA954x=y
 CONFIG_I2C_MUX_PINCTRL=y
 CONFIG_I2C_CADENCE=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_I2C_GPIO=m
 CONFIG_I2C_EXYNOS5=y
 CONFIG_I2C_MV64XXX=y
+CONFIG_I2C_RIIC=y
 CONFIG_I2C_S3C2410=y
+CONFIG_I2C_SH_MOBILE=y
 CONFIG_I2C_SIRF=y
-CONFIG_I2C_TEGRA=y
 CONFIG_I2C_ST=y
-CONFIG_SPI=y
+CONFIG_I2C_TEGRA=y
 CONFIG_I2C_XILINX=y
-CONFIG_SPI_DAVINCI=y
+CONFIG_I2C_RCAR=y
+CONFIG_SPI=y
 CONFIG_SPI_CADENCE=y
+CONFIG_SPI_DAVINCI=y
 CONFIG_SPI_OMAP24XX=y
 CONFIG_SPI_ORION=y
 CONFIG_SPI_PL022=y
+CONFIG_SPI_RSPI=y
+CONFIG_SPI_SH_MSIOF=m
+CONFIG_SPI_SH_HSPI=y
 CONFIG_SPI_SIRF=y
 CONFIG_SPI_SUN4I=y
 CONFIG_SPI_SUN6I=y
@@ -259,12 +290,15 @@ CONFIG_PINCTRL_PALMAS=y
 CONFIG_PINCTRL_APQ8084=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
-CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_DAVINCI=y
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_EM=y
+CONFIG_GPIO_RCAR=y
 CONFIG_GPIO_XILINX=y
 CONFIG_GPIO_ZYNQ=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCF857X=y
 CONFIG_GPIO_TWL4030=y
 CONFIG_GPIO_PALMAS=y
 CONFIG_GPIO_SYSCON=y
@@ -276,10 +310,12 @@ CONFIG_POWER_RESET_AS3722=y
 CONFIG_POWER_RESET_GPIO=y
 CONFIG_POWER_RESET_KEYSTONE=y
 CONFIG_POWER_RESET_SUN6I=y
+CONFIG_POWER_RESET_RMOBILE=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM95245=y
 CONFIG_THERMAL=y
 CONFIG_CPU_THERMAL=y
+CONFIG_RCAR_THERMAL=y
 CONFIG_ARMADA_THERMAL=y
 CONFIG_DAVINCI_WATCHDOG
 CONFIG_ST_THERMAL_SYSCFG=y
@@ -290,6 +326,7 @@ CONFIG_ARM_SP805_WATCHDOG=y
 CONFIG_ORION_WATCHDOG=y
 CONFIG_SUNXI_WATCHDOG=y
 CONFIG_MESON_WATCHDOG=y
+CONFIG_MFD_AS3711=y
 CONFIG_MFD_AS3722=y
 CONFIG_MFD_BCM590XX=y
 CONFIG_MFD_AXP20X=y
@@ -304,13 +341,16 @@ CONFIG_MFD_TPS65090=y
 CONFIG_MFD_TPS6586X=y
 CONFIG_MFD_TPS65910=y
 CONFIG_REGULATOR_AB8500=y
+CONFIG_REGULATOR_AS3711=y
 CONFIG_REGULATOR_AS3722=y
 CONFIG_REGULATOR_AXP20X=y
 CONFIG_REGULATOR_BCM590XX=y
+CONFIG_REGULATOR_DA9210=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MFD_SYSCON=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_REGULATOR_MAX8907=y
+CONFIG_REGULATOR_MAX8973=y
 CONFIG_REGULATOR_MAX77686=y
 CONFIG_REGULATOR_PALMAS=y
 CONFIG_REGULATOR_S2MPS11=y
@@ -324,18 +364,32 @@ CONFIG_REGULATOR_TWL4030=y
 CONFIG_REGULATOR_VEXPRESS=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=y
 CONFIG_USB_GSPCA=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=m
+CONFIG_SOC_CAMERA_PLATFORM=m
+CONFIG_VIDEO_RCAR_VIN=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_RENESAS_VSP1=m
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+CONFIG_VIDEO_ADV7180=m
 CONFIG_DRM=y
+CONFIG_DRM_RCAR_DU=m
 CONFIG_DRM_TEGRA=y
 CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_FB_ARMCLCD=y
 CONFIG_FB_WM8505=y
+CONFIG_FB_SH_MOBILE_LCDC=y
 CONFIG_FB_SIMPLE=y
+CONFIG_FB_SH_MOBILE_MERAM=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_AS3711=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_SOUND=y
@@ -343,6 +397,8 @@ CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SH4_FSI=m
+CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_TEGRA=y
 CONFIG_SND_SOC_TEGRA_RT5640=y
 CONFIG_SND_SOC_TEGRA_WM8753=y
@@ -350,6 +406,8 @@ CONFIG_SND_SOC_TEGRA_WM8903=y
 CONFIG_SND_SOC_TEGRA_TRIMSLICE=y
 CONFIG_SND_SOC_TEGRA_ALC5632=y
 CONFIG_SND_SOC_TEGRA_MAX98090=y
+CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_WM8978=m
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_MVEBU=y
@@ -362,6 +420,8 @@ CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_STI=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_RENESAS_USBHS=m
 CONFIG_USB_STORAGE=y
 CONFIG_USB_DWC3=y
 CONFIG_USB_CHIPIDEA=y
@@ -374,6 +434,10 @@ CONFIG_SAMSUNG_USB3PHY=y
 CONFIG_USB_GPIO_VBUS=y
 CONFIG_USB_ISP1301=y
 CONFIG_USB_MXS_PHY=y
+CONFIG_USB_RCAR_PHY=m
+CONFIG_USB_RCAR_GEN2_PHY=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS_UDC=m
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_ARMMMCI=y
@@ -392,12 +456,14 @@ CONFIG_MMC_SDHCI_ST=y
 CONFIG_MMC_OMAP=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_MMC_MVSDIO=y
-CONFIG_MMC_SUNXI=y
+CONFIG_MMC_SDHI=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_IDMAC=y
 CONFIG_MMC_DW_PLTFM=y
 CONFIG_MMC_DW_EXYNOS=y
 CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_MMC_SH_MMCIF=y
+CONFIG_MMC_SUNXI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
@@ -421,10 +487,12 @@ CONFIG_RTC_DRV_AS3722=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_MAX8907=y
 CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_RS5C372=m
 CONFIG_RTC_DRV_PALMAS=y
 CONFIG_RTC_DRV_TWL4030=y
 CONFIG_RTC_DRV_TPS6586X=y
 CONFIG_RTC_DRV_TPS65910=y
+CONFIG_RTC_DRV_S35390A=m
 CONFIG_RTC_DRV_EM3027=y
 CONFIG_RTC_DRV_PL031=y
 CONFIG_RTC_DRV_VT8500=y
@@ -436,6 +504,9 @@ CONFIG_DMADEVICES=y
 CONFIG_DW_DMAC=y
 CONFIG_MV_XOR=y
 CONFIG_TEGRA20_APB_DMA=y
+CONFIG_SH_DMAE=y
+CONFIG_RCAR_AUDMAC_PP=m
+CONFIG_RCAR_DMAC=y
 CONFIG_STE_DMA40=y
 CONFIG_SIRF_DMA=y
 CONFIG_TI_EDMA=y
@@ -468,6 +539,7 @@ CONFIG_IIO=y
 CONFIG_XILINX_XADC=y
 CONFIG_AK8975=y
 CONFIG_PWM=y
+CONFIG_PWM_RENESAS_TPU=y
 CONFIG_PWM_TEGRA=y
 CONFIG_PWM_VT8500=y
 CONFIG_PHY_HIX5HD2_SATA=y
index b738652..8e10859 100644 (file)
@@ -114,6 +114,7 @@ CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC_BCH=y
 CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_OMAP_BCH=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_OMAP2=y
@@ -248,6 +249,7 @@ CONFIG_TWL6040_CORE=y
 CONFIG_REGULATOR_PALMAS=y
 CONFIG_REGULATOR_PBIAS=y
 CONFIG_REGULATOR_TI_ABB=y
+CONFIG_REGULATOR_TPS62360=m
 CONFIG_REGULATOR_TPS65023=y
 CONFIG_REGULATOR_TPS6507X=y
 CONFIG_REGULATOR_TPS65217=y
@@ -374,7 +376,8 @@ CONFIG_PWM_TIEHRPWM=m
 CONFIG_PWM_TWL=m
 CONFIG_PWM_TWL_LED=m
 CONFIG_OMAP_USB2=m
-CONFIG_TI_PIPE3=m
+CONFIG_TI_PIPE3=y
+CONFIG_TWL4030_USB=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
index 41d856e..510c747 100644 (file)
@@ -3,8 +3,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
index 38840a8..8f6a570 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_PERF_EVENTS=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_SMP=y
+CONFIG_NR_CPUS=8
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_HIGHPTE=y
index f489fda..37fe607 100644 (file)
@@ -118,8 +118,8 @@ CONFIG_HID_ZEROPLUS=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_MON=y
-CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_ISP1760=y
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_NEW_LEDS=y
index 71e5fc7..1d1800f 100644 (file)
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__  7
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
 #endif
 
 #ifdef __thumb__
 # define adrl adr
 #endif
 
-#if __ARM_ARCH__>=7
+#if __ARM_MAX_ARCH__>=7
+.arch  armv7-a
+.fpu   neon
+
 .text
 .syntax        unified         @ ARMv7-capable assembler is expected to handle this
 #ifdef __thumb2__
@@ -74,8 +78,6 @@
 .code   32
 #endif
 
-.fpu   neon
-
 .type  _bsaes_decrypt8,%function
 .align 4
 _bsaes_decrypt8:
@@ -2095,9 +2097,11 @@ bsaes_xts_decrypt:
        vld1.8  {q8}, [r0]                      @ initial tweak
        adr     r2, .Lxts_magic
 
+#ifndef        XTS_CHAIN_TWEAK
        tst     r9, #0xf                        @ if not multiple of 16
        it      ne                              @ Thumb2 thing, sanity check in ARM
        subne   r9, #0x10                       @ subtract another 16 bytes
+#endif
        subs    r9, #0x80
 
        blo     .Lxts_dec_short
index be068db..a4d3856 100644 (file)
@@ -701,14 +701,18 @@ $code.=<<___;
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__  7
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
 #endif
 
 #ifdef __thumb__
 # define adrl adr
 #endif
 
-#if __ARM_ARCH__>=7
+#if __ARM_MAX_ARCH__>=7
+.arch  armv7-a
+.fpu   neon
+
 .text
 .syntax        unified         @ ARMv7-capable assembler is expected to handle this
 #ifdef __thumb2__
@@ -717,8 +721,6 @@ $code.=<<___;
 .code   32
 #endif
 
-.fpu   neon
-
 .type  _bsaes_decrypt8,%function
 .align 4
 _bsaes_decrypt8:
@@ -2076,9 +2078,11 @@ bsaes_xts_decrypt:
        vld1.8  {@XMM[8]}, [r0]                 @ initial tweak
        adr     $magic, .Lxts_magic
 
+#ifndef        XTS_CHAIN_TWEAK
        tst     $len, #0xf                      @ if not multiple of 16
        it      ne                              @ Thumb2 thing, sanity check in ARM
        subne   $len, #0x10                     @ subtract another 16 bytes
+#endif
        subs    $len, #0x80
 
        blo     .Lxts_dec_short
index 37ca2a4..4cf48c3 100644 (file)
@@ -149,29 +149,28 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
        (__boundary - 1 < (end) - 1)? __boundary: (end);                \
 })
 
+#define kvm_pgd_index(addr)                    pgd_index(addr)
+
 static inline bool kvm_page_empty(void *ptr)
 {
        struct page *ptr_page = virt_to_page(ptr);
        return page_count(ptr_page) == 1;
 }
 
-
 #define kvm_pte_table_empty(kvm, ptep) kvm_page_empty(ptep)
 #define kvm_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp)
 #define kvm_pud_table_empty(kvm, pudp) (0)
 
 #define KVM_PREALLOC_LEVEL     0
 
-static inline int kvm_prealloc_hwpgd(struct kvm *kvm, pgd_t *pgd)
+static inline void *kvm_get_hwpgd(struct kvm *kvm)
 {
-       return 0;
+       return kvm->arch.pgd;
 }
 
-static inline void kvm_free_hwpgd(struct kvm *kvm) { }
-
-static inline void *kvm_get_hwpgd(struct kvm *kvm)
+static inline unsigned int kvm_get_hwpgd_size(void)
 {
-       return kvm->arch.pgd;
+       return PTRS_PER_S2_PGD * sizeof(pgd_t);
 }
 
 struct kvm;
@@ -207,7 +206,7 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
 
        bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached;
 
-       VM_BUG_ON(size & PAGE_MASK);
+       VM_BUG_ON(size & ~PAGE_MASK);
 
        if (!need_flush && !icache_is_pipt())
                goto vipt_cache;
index 80a6501..c3c45e6 100644 (file)
 #define AT91_DBGU 0xfc00c000 /* SAMA5D4_BASE_USART3 */
 #endif
 
-/* Keep in sync with mach-at91/include/mach/hardware.h */
+#ifdef CONFIG_MMU
 #define AT91_IO_P2V(x) ((x) - 0x01000000)
+#else
+#define AT91_IO_P2V(x) (x)
+#endif
 
 #define AT91_DBGU_SR           (0x14)  /* Status Register */
 #define AT91_DBGU_THR          (0x1c)  /* Transmitter Holding Register */
index e55408e..1d60beb 100644 (file)
@@ -246,12 +246,9 @@ static int __get_cpu_architecture(void)
                if (cpu_arch)
                        cpu_arch += CPU_ARCH_ARMv3;
        } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
-               unsigned int mmfr0;
-
                /* Revised CPUID format. Read the Memory Model Feature
                 * Register 0 and check for VMSAv7 or PMSAv7 */
-               asm("mrc        p15, 0, %0, c0, c1, 4"
-                   : "=r" (mmfr0));
+               unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0);
                if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
                    (mmfr0 & 0x000000f0) >= 0x00000030)
                        cpu_arch = CPU_ARCH_ARMv7;
index 07e7eb1..5560f74 100644 (file)
@@ -540,7 +540,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                kvm_guest_exit();
-               trace_kvm_exit(*vcpu_pc(vcpu));
+               trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
                /*
                 * We may have taken a host interrupt in HYP mode (ie
                 * while executing the guest). This interrupt is still
index 3e6859b..5656d79 100644 (file)
@@ -290,7 +290,7 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
        phys_addr_t addr = start, end = start + size;
        phys_addr_t next;
 
-       pgd = pgdp + pgd_index(addr);
+       pgd = pgdp + kvm_pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
                if (!pgd_none(*pgd))
@@ -355,7 +355,7 @@ static void stage2_flush_memslot(struct kvm *kvm,
        phys_addr_t next;
        pgd_t *pgd;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
                stage2_flush_puds(kvm, pgd, addr, next);
@@ -632,6 +632,20 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
                                     __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
 }
 
+/* Free the HW pgd, one page at a time */
+static void kvm_free_hwpgd(void *hwpgd)
+{
+       free_pages_exact(hwpgd, kvm_get_hwpgd_size());
+}
+
+/* Allocate the HW PGD, making sure that each page gets its own refcount */
+static void *kvm_alloc_hwpgd(void)
+{
+       unsigned int size = kvm_get_hwpgd_size();
+
+       return alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+}
+
 /**
  * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
  * @kvm:       The KVM struct pointer for the VM.
@@ -645,15 +659,31 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
  */
 int kvm_alloc_stage2_pgd(struct kvm *kvm)
 {
-       int ret;
        pgd_t *pgd;
+       void *hwpgd;
 
        if (kvm->arch.pgd != NULL) {
                kvm_err("kvm_arch already initialized?\n");
                return -EINVAL;
        }
 
+       hwpgd = kvm_alloc_hwpgd();
+       if (!hwpgd)
+               return -ENOMEM;
+
+       /* When the kernel uses more levels of page tables than the
+        * guest, we allocate a fake PGD and pre-populate it to point
+        * to the next-level page table, which will be the real
+        * initial page table pointed to by the VTTBR.
+        *
+        * When KVM_PREALLOC_LEVEL==2, we allocate a single page for
+        * the PMD and the kernel will use folded pud.
+        * When KVM_PREALLOC_LEVEL==1, we allocate 2 consecutive PUD
+        * pages.
+        */
        if (KVM_PREALLOC_LEVEL > 0) {
+               int i;
+
                /*
                 * Allocate fake pgd for the page table manipulation macros to
                 * work.  This is not used by the hardware and we have no
@@ -661,30 +691,32 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
                 */
                pgd = (pgd_t *)kmalloc(PTRS_PER_S2_PGD * sizeof(pgd_t),
                                       GFP_KERNEL | __GFP_ZERO);
+
+               if (!pgd) {
+                       kvm_free_hwpgd(hwpgd);
+                       return -ENOMEM;
+               }
+
+               /* Plug the HW PGD into the fake one. */
+               for (i = 0; i < PTRS_PER_S2_PGD; i++) {
+                       if (KVM_PREALLOC_LEVEL == 1)
+                               pgd_populate(NULL, pgd + i,
+                                            (pud_t *)hwpgd + i * PTRS_PER_PUD);
+                       else if (KVM_PREALLOC_LEVEL == 2)
+                               pud_populate(NULL, pud_offset(pgd, 0) + i,
+                                            (pmd_t *)hwpgd + i * PTRS_PER_PMD);
+               }
        } else {
                /*
                 * Allocate actual first-level Stage-2 page table used by the
                 * hardware for Stage-2 page table walks.
                 */
-               pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, S2_PGD_ORDER);
+               pgd = (pgd_t *)hwpgd;
        }
 
-       if (!pgd)
-               return -ENOMEM;
-
-       ret = kvm_prealloc_hwpgd(kvm, pgd);
-       if (ret)
-               goto out_err;
-
        kvm_clean_pgd(pgd);
        kvm->arch.pgd = pgd;
        return 0;
-out_err:
-       if (KVM_PREALLOC_LEVEL > 0)
-               kfree(pgd);
-       else
-               free_pages((unsigned long)pgd, S2_PGD_ORDER);
-       return ret;
 }
 
 /**
@@ -785,11 +817,10 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
                return;
 
        unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
-       kvm_free_hwpgd(kvm);
+       kvm_free_hwpgd(kvm_get_hwpgd(kvm));
        if (KVM_PREALLOC_LEVEL > 0)
                kfree(kvm->arch.pgd);
-       else
-               free_pages((unsigned long)kvm->arch.pgd, S2_PGD_ORDER);
+
        kvm->arch.pgd = NULL;
 }
 
@@ -799,7 +830,7 @@ static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache
        pgd_t *pgd;
        pud_t *pud;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        if (WARN_ON(pgd_none(*pgd))) {
                if (!cache)
                        return NULL;
@@ -1089,7 +1120,7 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
        pgd_t *pgd;
        phys_addr_t next;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        do {
                /*
                 * Release kvm_mmu_lock periodically if the memory region is
index 881874b..6817664 100644 (file)
@@ -25,18 +25,22 @@ TRACE_EVENT(kvm_entry,
 );
 
 TRACE_EVENT(kvm_exit,
-       TP_PROTO(unsigned long vcpu_pc),
-       TP_ARGS(vcpu_pc),
+       TP_PROTO(unsigned int exit_reason, unsigned long vcpu_pc),
+       TP_ARGS(exit_reason, vcpu_pc),
 
        TP_STRUCT__entry(
+               __field(        unsigned int,   exit_reason     )
                __field(        unsigned long,  vcpu_pc         )
        ),
 
        TP_fast_assign(
+               __entry->exit_reason            = exit_reason;
                __entry->vcpu_pc                = vcpu_pc;
        ),
 
-       TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
+       TP_printk("HSR_EC: 0x%04x, PC: 0x%08lx",
+                 __entry->exit_reason,
+                 __entry->vcpu_pc)
 );
 
 TRACE_EVENT(kvm_guest_fault,
index 8423be7..5224120 100644 (file)
@@ -2,5 +2,7 @@ config MACH_ASM9260
        bool "Alphascale ASM9260"
        depends on ARCH_MULTI_V5
        select CPU_ARM926T
+       select ASM9260_TIMER
+       select GENERIC_CLOCKEVENTS
        help
          Support for Alphascale ASM9260 based platform.
index 5e34fb1..aa4116e 100644 (file)
@@ -270,37 +270,35 @@ static void __init at91_pm_sram_init(void)
        phys_addr_t sram_pbase;
        unsigned long sram_base;
        struct device_node *node;
-       struct platform_device *pdev;
+       struct platform_device *pdev = NULL;
 
-       node = of_find_compatible_node(NULL, NULL, "mmio-sram");
-       if (!node) {
-               pr_warn("%s: failed to find sram node!\n", __func__);
-               return;
+       for_each_compatible_node(node, NULL, "mmio-sram") {
+               pdev = of_find_device_by_node(node);
+               if (pdev) {
+                       of_node_put(node);
+                       break;
+               }
        }
 
-       pdev = of_find_device_by_node(node);
        if (!pdev) {
                pr_warn("%s: failed to find sram device!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_pool = dev_get_gen_pool(&pdev->dev);
        if (!sram_pool) {
                pr_warn("%s: sram pool unavailable!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_base = gen_pool_alloc(sram_pool, at91_slow_clock_sz);
        if (!sram_base) {
                pr_warn("%s: unable to alloc ocram!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base);
        slow_clock = __arm_ioremap_exec(sram_pbase, at91_slow_clock_sz, false);
-
-put_node:
-       of_node_put(node);
 }
 #endif
 
index d2c8996..86c0aa8 100644 (file)
@@ -44,7 +44,7 @@ static inline void at91rm9200_standby(void)
                "    mcr    p15, 0, %0, c7, c0, 4\n\t"
                "    str    %5, [%1, %2]"
                :
-               : "r" (0), "r" (AT91_BASE_SYS), "r" (AT91RM9200_SDRAMC_LPR),
+               : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91RM9200_SDRAMC_LPR),
                  "r" (1), "r" (AT91RM9200_SDRAMC_SRR),
                  "r" (lpr));
 }
index 556151e..931f0e3 100644 (file)
  */
 #undef SLOWDOWN_MASTER_CLOCK
 
-#define MCKRDY_TIMEOUT         1000
-#define MOSCRDY_TIMEOUT        1000
-#define PLLALOCK_TIMEOUT       1000
-#define PLLBLOCK_TIMEOUT       1000
-
 pmc    .req    r0
 sdramc .req    r1
 ramc1  .req    r2
@@ -41,60 +36,42 @@ tmp2        .req    r5
  * Wait until master clock is ready (after switching master clock source)
  */
        .macro wait_mckrdy
-       mov     tmp2, #MCKRDY_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_MCKRDY
        beq     1b
-2:
        .endm
 
 /*
  * Wait until master oscillator has stabilized.
  */
        .macro wait_moscrdy
-       mov     tmp2, #MOSCRDY_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_MOSCS
        beq     1b
-2:
        .endm
 
 /*
  * Wait until PLLA has locked.
  */
        .macro wait_pllalock
-       mov     tmp2, #PLLALOCK_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_LOCKA
        beq     1b
-2:
        .endm
 
 /*
  * Wait until PLLB has locked.
  */
        .macro wait_pllblock
-       mov     tmp2, #PLLBLOCK_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_LOCKB
        beq     1b
-2:
        .endm
 
        .text
 
+       .arm
+
 /* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
  *                     void __iomem *ramc1, int memctrl)
  */
@@ -134,6 +111,16 @@ ddr_sr_enable:
        cmp     memctrl, #AT91_MEMCTRL_DDRSDR
        bne     sdr_sr_enable
 
+       /* LPDDR1 --> force DDR2 mode during self-refresh */
+       ldr     tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+       str     tmp1, .saved_sam9_mdr
+       bic     tmp1, tmp1, #~AT91_DDRSDRC_MD
+       cmp     tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+       ldreq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+       biceq   tmp1, tmp1, #AT91_DDRSDRC_MD
+       orreq   tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
+       streq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+
        /* prepare for DDRAM self-refresh mode */
        ldr     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
        str     tmp1, .saved_sam9_lpr
@@ -142,14 +129,26 @@ ddr_sr_enable:
 
        /* figure out if we use the second ram controller */
        cmp     ramc1, #0
-       ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-       strne   tmp2, .saved_sam9_lpr1
-       bicne   tmp2, #AT91_DDRSDRC_LPCB
-       orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+       beq     ddr_no_2nd_ctrl
+
+       ldr     tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+       str     tmp2, .saved_sam9_mdr1
+       bic     tmp2, tmp2, #~AT91_DDRSDRC_MD
+       cmp     tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+       ldreq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+       biceq   tmp2, tmp2, #AT91_DDRSDRC_MD
+       orreq   tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
+       streq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+
+       ldr     tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+       str     tmp2, .saved_sam9_lpr1
+       bic     tmp2, #AT91_DDRSDRC_LPCB
+       orr     tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
        /* Enable DDRAM self-refresh mode */
+       str     tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+ddr_no_2nd_ctrl:
        str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-       strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
        b       sdr_sr_done
 
@@ -208,6 +207,7 @@ sdr_sr_done:
        /* Turn off the main oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
        bic     tmp1, tmp1, #AT91_PMC_MOSCEN
+       orr     tmp1, tmp1, #AT91_PMC_KEY
        str     tmp1, [pmc, #AT91_CKGR_MOR]
 
        /* Wait for interrupt */
@@ -216,6 +216,7 @@ sdr_sr_done:
        /* Turn on the main oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
        orr     tmp1, tmp1, #AT91_PMC_MOSCEN
+       orr     tmp1, tmp1, #AT91_PMC_KEY
        str     tmp1, [pmc, #AT91_CKGR_MOR]
 
        wait_moscrdy
@@ -280,12 +281,17 @@ sdr_sr_done:
         */
        cmp     memctrl, #AT91_MEMCTRL_DDRSDR
        bne     sdr_en_restore
+       /* Restore MDR in case of LPDDR1 */
+       ldr     tmp1, .saved_sam9_mdr
+       str     tmp1, [sdramc, #AT91_DDRSDRC_MDR]
        /* Restore LPR on AT91 with DDRAM */
        ldr     tmp1, .saved_sam9_lpr
        str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 
        /* if we use the second ram controller */
        cmp     ramc1, #0
+       ldrne   tmp2, .saved_sam9_mdr1
+       strne   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
        ldrne   tmp2, .saved_sam9_lpr1
        strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
@@ -319,5 +325,11 @@ ram_restored:
 .saved_sam9_lpr1:
        .word 0
 
+.saved_sam9_mdr:
+       .word 0
+
+.saved_sam9_mdr1:
+       .word 0
+
 ENTRY(at91_slow_clock_sz)
        .word .-at91_slow_clock
index 3f32c47..d2e9f12 100644 (file)
@@ -126,8 +126,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
  */
 void exynos_cpu_power_down(int cpu)
 {
-       if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") ||
-               of_machine_is_compatible("samsung,exynos5800"))) {
+       if (cpu == 0 && (soc_is_exynos5420() || soc_is_exynos5800())) {
                /*
                 * Bypass power down for CPU0 during suspend. Check for
                 * the SYS_PWR_REG value to decide if we are suspending
index 20f2671..37266a8 100644 (file)
@@ -161,6 +161,34 @@ no_clk:
                of_genpd_add_provider_simple(np, &pd->pd);
        }
 
+       /* Assign the child power domains to their parents */
+       for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
+               struct generic_pm_domain *child_domain, *parent_domain;
+               struct of_phandle_args args;
+
+               args.np = np;
+               args.args_count = 0;
+               child_domain = of_genpd_get_from_provider(&args);
+               if (!child_domain)
+                       continue;
+
+               if (of_parse_phandle_with_args(np, "power-domains",
+                                        "#power-domain-cells", 0, &args) != 0)
+                       continue;
+
+               parent_domain = of_genpd_get_from_provider(&args);
+               if (!parent_domain)
+                       continue;
+
+               if (pm_genpd_add_subdomain(parent_domain, child_domain))
+                       pr_warn("%s failed to add subdomain: %s\n",
+                               parent_domain->name, child_domain->name);
+               else
+                       pr_info("%s has as child subdomain: %s.\n",
+                               parent_domain->name, child_domain->name);
+               of_node_put(np);
+       }
+
        return 0;
 }
 arch_initcall(exynos4_pm_init_power_domain);
index 52e2b1a..318d127 100644 (file)
@@ -87,8 +87,8 @@ static unsigned int exynos_pmu_spare3;
 static u32 exynos_irqwake_intmask = 0xffffffff;
 
 static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
-       { 73, BIT(1) }, /* RTC alarm */
-       { 74, BIT(2) }, /* RTC tick */
+       { 105, BIT(1) }, /* RTC alarm */
+       { 106, BIT(2) }, /* RTC tick */
        { /* sentinel */ },
 };
 
index 4ad6e47..9de3412 100644 (file)
@@ -211,8 +211,9 @@ static void __init imx6q_1588_init(void)
         * set bit IOMUXC_GPR1[21].  Or the PTP clock must be from pad
         * (external OSC), and we need to clear the bit.
         */
-       clksel = ptp_clk == enet_ref ? IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
-                                      IMX6Q_GPR1_ENET_CLK_SEL_PAD;
+       clksel = clk_is_match(ptp_clk, enet_ref) ?
+                               IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
+                               IMX6Q_GPR1_ENET_CLK_SEL_PAD;
        gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
        if (!IS_ERR(gpr))
                regmap_update_bits(gpr, IOMUXC_GPR1,
index 61bfe58..fc83204 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/smc91x.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -46,15 +47,20 @@ static struct resource smc91x_resources[] = {
        [1] = {
                .start  = MSM_GPIO_TO_INT(49),
                .end    = MSM_GPIO_TO_INT(49),
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static struct platform_device *devices[] __initdata = {
index 4c74861..10016a3 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/usb/msm_hsusb.h>
 #include <linux/err.h>
 #include <linux/clkdev.h>
+#include <linux/smc91x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -49,15 +50,20 @@ static struct resource smc91x_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        [1] = {
-               .flags = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static int __init msm_init_smc91x(void)
index 2a2f4d5..25f1bee 100644 (file)
@@ -720,6 +720,8 @@ static const char * __init omap_get_family(void)
                return kasprintf(GFP_KERNEL, "OMAP4");
        else if (soc_is_omap54xx())
                return kasprintf(GFP_KERNEL, "OMAP5");
+       else if (soc_is_am33xx() || soc_is_am335x())
+               return kasprintf(GFP_KERNEL, "AM33xx");
        else if (soc_is_am43xx())
                return kasprintf(GFP_KERNEL, "AM43xx");
        else if (soc_is_dra7xx())
index 92afb72..355b089 100644 (file)
@@ -1692,16 +1692,15 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
        if (ret == -EBUSY)
                pr_warn("omap_hwmod: %s: failed to hardreset\n", oh->name);
 
-       if (!ret) {
+       if (oh->clkdm) {
                /*
                 * Set the clockdomain to HW_AUTO, assuming that the
                 * previous state was HW_AUTO.
                 */
-               if (oh->clkdm && hwsup)
+               if (hwsup)
                        clkdm_allow_idle(oh->clkdm);
-       } else {
-               if (oh->clkdm)
-                       clkdm_hwmod_disable(oh->clkdm, oh);
+
+               clkdm_hwmod_disable(oh->clkdm, oh);
        }
 
        return ret;
@@ -2698,6 +2697,7 @@ static int __init _register(struct omap_hwmod *oh)
        INIT_LIST_HEAD(&oh->master_ports);
        INIT_LIST_HEAD(&oh->slave_ports);
        spin_lock_init(&oh->_lock);
+       lockdep_set_class(&oh->_lock, &oh->hwmod_key);
 
        oh->_state = _HWMOD_STATE_REGISTERED;
 
index 9d4bec6..9611c91 100644 (file)
@@ -674,6 +674,7 @@ struct omap_hwmod {
        u32                             _sysc_cache;
        void __iomem                    *_mpu_rt_va;
        spinlock_t                      _lock;
+       struct lock_class_key           hwmod_key; /* unique lock class */
        struct list_head                node;
        struct omap_hwmod_ocp_if        *_mpu_port;
        unsigned int                    (*xlate_irq)(unsigned int);
index e8692e7..16fe7a1 100644 (file)
@@ -1466,53 +1466,16 @@ static struct omap_hwmod dra7xx_ocp2scp3_hwmod = {
  *
  */
 
-static struct omap_hwmod_class dra7xx_pcie_hwmod_class = {
+static struct omap_hwmod_class dra7xx_pciess_hwmod_class = {
        .name   = "pcie",
 };
 
 /* pcie1 */
-static struct omap_hwmod dra7xx_pcie1_hwmod = {
+static struct omap_hwmod dra7xx_pciess1_hwmod = {
        .name           = "pcie1",
-       .class          = &dra7xx_pcie_hwmod_class,
+       .class          = &dra7xx_pciess_hwmod_class,
        .clkdm_name     = "pcie_clkdm",
        .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs   = DRA7XX_CM_PCIE_CLKSTCTRL_OFFSET,
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* pcie2 */
-static struct omap_hwmod dra7xx_pcie2_hwmod = {
-       .name           = "pcie2",
-       .class          = &dra7xx_pcie_hwmod_class,
-       .clkdm_name     = "pcie_clkdm",
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_PCIE_CLKSTCTRL_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/*
- * 'PCIE PHY' class
- *
- */
-
-static struct omap_hwmod_class dra7xx_pcie_phy_hwmod_class = {
-       .name   = "pcie-phy",
-};
-
-/* pcie1 phy */
-static struct omap_hwmod dra7xx_pcie1_phy_hwmod = {
-       .name           = "pcie1-phy",
-       .class          = &dra7xx_pcie_phy_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
-       .main_clk       = "l4_root_clk_div",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = DRA7XX_CM_L3INIT_PCIESS1_CLKCTRL_OFFSET,
@@ -1522,11 +1485,11 @@ static struct omap_hwmod dra7xx_pcie1_phy_hwmod = {
        },
 };
 
-/* pcie2 phy */
-static struct omap_hwmod dra7xx_pcie2_phy_hwmod = {
-       .name           = "pcie2-phy",
-       .class          = &dra7xx_pcie_phy_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
+/* pcie2 */
+static struct omap_hwmod dra7xx_pciess2_hwmod = {
+       .name           = "pcie2",
+       .class          = &dra7xx_pciess_hwmod_class,
+       .clkdm_name     = "pcie_clkdm",
        .main_clk       = "l4_root_clk_div",
        .prcm = {
                .omap4 = {
@@ -2877,50 +2840,34 @@ static struct omap_hwmod_ocp_if dra7xx_l4_cfg__ocp2scp3 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_1 -> pcie1 */
-static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pcie1 = {
+/* l3_main_1 -> pciess1 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pciess1 = {
        .master         = &dra7xx_l3_main_1_hwmod,
-       .slave          = &dra7xx_pcie1_hwmod,
+       .slave          = &dra7xx_pciess1_hwmod,
        .clk            = "l3_iclk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> pcie1 */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie1 = {
+/* l4_cfg -> pciess1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pciess1 = {
        .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie1_hwmod,
+       .slave          = &dra7xx_pciess1_hwmod,
        .clk            = "l4_root_clk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_1 -> pcie2 */
-static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pcie2 = {
+/* l3_main_1 -> pciess2 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pciess2 = {
        .master         = &dra7xx_l3_main_1_hwmod,
-       .slave          = &dra7xx_pcie2_hwmod,
+       .slave          = &dra7xx_pciess2_hwmod,
        .clk            = "l3_iclk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> pcie2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie2 = {
-       .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie2_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg -> pcie1 phy */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie1_phy = {
-       .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie1_phy_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg -> pcie2 phy */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie2_phy = {
+/* l4_cfg -> pciess2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pciess2 = {
        .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie2_phy_hwmod,
+       .slave          = &dra7xx_pciess2_hwmod,
        .clk            = "l4_root_clk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
@@ -3327,12 +3274,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_cfg__mpu,
        &dra7xx_l4_cfg__ocp2scp1,
        &dra7xx_l4_cfg__ocp2scp3,
-       &dra7xx_l3_main_1__pcie1,
-       &dra7xx_l4_cfg__pcie1,
-       &dra7xx_l3_main_1__pcie2,
-       &dra7xx_l4_cfg__pcie2,
-       &dra7xx_l4_cfg__pcie1_phy,
-       &dra7xx_l4_cfg__pcie2_phy,
+       &dra7xx_l3_main_1__pciess1,
+       &dra7xx_l4_cfg__pciess1,
+       &dra7xx_l3_main_1__pciess2,
+       &dra7xx_l4_cfg__pciess2,
        &dra7xx_l3_main_1__qspi,
        &dra7xx_l4_per3__rtcss,
        &dra7xx_l4_cfg__sata,
index 190fa43..e642b07 100644 (file)
@@ -173,6 +173,7 @@ static void __init omap3_igep0030_rev_g_legacy_init(void)
 
 static void __init omap3_evm_legacy_init(void)
 {
+       hsmmc2_internal_input_clk();
        legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 149);
 }
 
index a08a617..d6d6bc3 100644 (file)
@@ -252,10 +252,10 @@ static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
 {
        saved_mask[0] =
                omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
-                                       OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
+                                       OMAP4_PRM_IRQENABLE_MPU_OFFSET);
        saved_mask[1] =
                omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
-                                       OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET);
+                                       OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 
        omap4_prm_write_inst_reg(0, OMAP4430_PRM_OCP_SOCKET_INST,
                                 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
index 343c4e3..f6d02e4 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/platform_data/video-pxafb.h>
 #include <mach/bitfield.h>
 #include <linux/platform_data/mmc-pxamci.h>
+#include <linux/smc91x.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -81,11 +82,16 @@ static struct resource smc91x_resources[] = {
        }
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_32BIT | SMC91X_USE_DMA | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static void idp_backlight_power(int on)
index 0eecd83..89a7c06 100644 (file)
@@ -11,6 +11,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
+#include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -40,7 +41,6 @@
 #define ICHP_VAL_IRQ           (1 << 31)
 #define ICHP_IRQ(i)            (((i) >> 16) & 0x7fff)
 #define IPR_VALID              (1 << 31)
-#define IRQ_BIT(n)             (((n) - PXA_IRQ(0)) & 0x1f)
 
 #define MAX_INTERNAL_IRQS      128
 
@@ -51,6 +51,7 @@
 static void __iomem *pxa_irq_base;
 static int pxa_internal_irq_nr;
 static bool cpu_has_ipr;
+static struct irq_domain *pxa_irq_domain;
 
 static inline void __iomem *irq_base(int i)
 {
@@ -66,18 +67,20 @@ static inline void __iomem *irq_base(int i)
 void pxa_mask_irq(struct irq_data *d)
 {
        void __iomem *base = irq_data_get_irq_chip_data(d);
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        uint32_t icmr = __raw_readl(base + ICMR);
 
-       icmr &= ~(1 << IRQ_BIT(d->irq));
+       icmr &= ~BIT(irq & 0x1f);
        __raw_writel(icmr, base + ICMR);
 }
 
 void pxa_unmask_irq(struct irq_data *d)
 {
        void __iomem *base = irq_data_get_irq_chip_data(d);
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        uint32_t icmr = __raw_readl(base + ICMR);
 
-       icmr |= 1 << IRQ_BIT(d->irq);
+       icmr |= BIT(irq & 0x1f);
        __raw_writel(icmr, base + ICMR);
 }
 
@@ -118,40 +121,63 @@ asmlinkage void __exception_irq_entry ichp_handle_irq(struct pt_regs *regs)
        } while (1);
 }
 
-void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
+static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
+                      irq_hw_number_t hw)
 {
-       int irq, i, n;
+       void __iomem *base = irq_base(hw / 32);
 
-       BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
+       /* initialize interrupt priority */
+       if (cpu_has_ipr)
+               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
+
+       irq_set_chip_and_handler(virq, &pxa_internal_irq_chip,
+                                handle_level_irq);
+       irq_set_chip_data(virq, base);
+       set_irq_flags(virq, IRQF_VALID);
+
+       return 0;
+}
+
+static struct irq_domain_ops pxa_irq_ops = {
+       .map    = pxa_irq_map,
+       .xlate  = irq_domain_xlate_onecell,
+};
+
+static __init void
+pxa_init_irq_common(struct device_node *node, int irq_nr,
+                   int (*fn)(struct irq_data *, unsigned int))
+{
+       int n;
 
        pxa_internal_irq_nr = irq_nr;
-       cpu_has_ipr = !cpu_is_pxa25x();
-       pxa_irq_base = io_p2v(0x40d00000);
+       pxa_irq_domain = irq_domain_add_legacy(node, irq_nr,
+                                              PXA_IRQ(0), 0,
+                                              &pxa_irq_ops, NULL);
+       if (!pxa_irq_domain)
+               panic("Unable to add PXA IRQ domain\n");
+       irq_set_default_host(pxa_irq_domain);
 
        for (n = 0; n < irq_nr; n += 32) {
                void __iomem *base = irq_base(n >> 5);
 
                __raw_writel(0, base + ICMR);   /* disable all IRQs */
                __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
-               for (i = n; (i < (n + 32)) && (i < irq_nr); i++) {
-                       /* initialize interrupt priority */
-                       if (cpu_has_ipr)
-                               __raw_writel(i | IPR_VALID, pxa_irq_base + IPR(i));
-
-                       irq = PXA_IRQ(i);
-                       irq_set_chip_and_handler(irq, &pxa_internal_irq_chip,
-                                                handle_level_irq);
-                       irq_set_chip_data(irq, base);
-                       set_irq_flags(irq, IRQF_VALID);
-               }
        }
-
        /* only unmasked interrupts kick us out of idle */
        __raw_writel(1, irq_base(0) + ICCR);
 
        pxa_internal_irq_chip.irq_set_wake = fn;
 }
 
+void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
+{
+       BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
+
+       pxa_irq_base = io_p2v(0x40d00000);
+       cpu_has_ipr = !cpu_is_pxa25x();
+       pxa_init_irq_common(NULL, irq_nr, fn);
+}
+
 #ifdef CONFIG_PM
 static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
 static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
@@ -203,30 +229,6 @@ struct syscore_ops pxa_irq_syscore_ops = {
 };
 
 #ifdef CONFIG_OF
-static struct irq_domain *pxa_irq_domain;
-
-static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
-                      irq_hw_number_t hw)
-{
-       void __iomem *base = irq_base(hw / 32);
-
-       /* initialize interrupt priority */
-       if (cpu_has_ipr)
-               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
-
-       irq_set_chip_and_handler(hw, &pxa_internal_irq_chip,
-                                handle_level_irq);
-       irq_set_chip_data(hw, base);
-       set_irq_flags(hw, IRQF_VALID);
-
-       return 0;
-}
-
-static struct irq_domain_ops pxa_irq_ops = {
-       .map    = pxa_irq_map,
-       .xlate  = irq_domain_xlate_onecell,
-};
-
 static const struct of_device_id intc_ids[] __initconst = {
        { .compatible = "marvell,pxa-intc", },
        {}
@@ -236,7 +238,7 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
 {
        struct device_node *node;
        struct resource res;
-       int n, ret;
+       int ret;
 
        node = of_find_matching_node(NULL, intc_ids);
        if (!node) {
@@ -267,23 +269,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
                return;
        }
 
-       pxa_irq_domain = irq_domain_add_legacy(node, pxa_internal_irq_nr, 0, 0,
-                                              &pxa_irq_ops, NULL);
-       if (!pxa_irq_domain)
-               panic("Unable to add PXA IRQ domain\n");
-
-       irq_set_default_host(pxa_irq_domain);
-
-       for (n = 0; n < pxa_internal_irq_nr; n += 32) {
-               void __iomem *base = irq_base(n >> 5);
-
-               __raw_writel(0, base + ICMR);   /* disable all IRQs */
-               __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
-       }
-
-       /* only unmasked interrupts kick us out of idle */
-       __raw_writel(1, irq_base(0) + ICCR);
-
-       pxa_internal_irq_chip.irq_set_wake = fn;
+       pxa_init_irq_common(node, pxa_internal_irq_nr, fn);
 }
 #endif /* CONFIG_OF */
index ad777b3..eaee2c2 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/pwm_backlight.h>
+#include <linux/smc91x.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -189,15 +190,20 @@ static struct resource smc91x_resources[] = {
        [1] = {
                .start  = LPD270_ETHERNET_IRQ,
                .end    = LPD270_ETHERNET_IRQ,
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
 };
 
+struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static struct resource lpd270_flash_resources[] = {
index 205f9bf..ac2ae5c 100644 (file)
@@ -412,7 +412,7 @@ static struct fixed_voltage_config can_regulator_pdata = {
 };
 
 static struct platform_device can_regulator_device = {
-       .name   = "reg-fixed-volage",
+       .name   = "reg-fixed-voltage",
        .id     = 0,
        .dev    = {
                .platform_data  = &can_regulator_pdata,
index 850e506..c309593 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/platform_data/video-clcd-versatile.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/smc91x.h>
 #include <linux/ata_platform.h>
 #include <linux/amba/mmci.h>
 #include <linux/gfp.h>
@@ -94,6 +95,10 @@ static struct smsc911x_platform_config smsc911x_config = {
        .phy_interface  = PHY_INTERFACE_MODE_MII,
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device realview_eth_device = {
        .name           = "smsc911x",
        .id             = 0,
@@ -107,6 +112,8 @@ int realview_eth_register(const char *name, struct resource *res)
        realview_eth_device.resource = res;
        if (strcmp(realview_eth_device.name, "smsc911x") == 0)
                realview_eth_device.dev.platform_data = &smsc911x_config;
+       else
+               realview_eth_device.dev.platform_data = &smc91x_platdata;
 
        return platform_device_register(&realview_eth_device);
 }
index 64c88d6..b3869cb 100644 (file)
@@ -234,7 +234,7 @@ static struct resource realview_eb_eth_resources[] = {
        [1] = {
                .start          = IRQ_EB_ETH,
                .end            = IRQ_EB_ETH,
-               .flags          = IORESOURCE_IRQ,
+               .flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
 };
 
index 169262e..af868d2 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pm.h>
 #include <linux/serial_core.h>
 #include <linux/slab.h>
+#include <linux/smc91x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
@@ -258,12 +259,17 @@ static int neponset_probe(struct platform_device *dev)
                        0x02000000, "smc91x-attrib"),
                { .flags = IORESOURCE_IRQ },
        };
+       struct smc91x_platdata smc91x_platdata = {
+               .flags = SMC91X_USE_8BIT | SMC91X_IO_SHIFT_2 | SMC91X_NOWAIT,
+       };
        struct platform_device_info smc91x_devinfo = {
                .parent = &dev->dev,
                .name = "smc91x",
                .id = 0,
                .res = smc91x_resources,
                .num_res = ARRAY_SIZE(smc91x_resources),
+               .data = &smc91x_platdata,
+               .size_data = sizeof(smc91x_platdata),
        };
        int ret, irq;
 
index 0912618..1525d7b 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/mtd/partitions.h>
+#include <linux/smc91x.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -43,12 +44,18 @@ static struct resource smc91x_resources[] = {
 #endif
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
 
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev = {
+               .platform_data  = &smc91x_platdata,
+       },
 };
 
 static struct platform_device *devices[] __initdata = {
index 483cb46..a0f3b1c 100644 (file)
@@ -45,6 +45,6 @@ extern char secondary_trampoline, secondary_trampoline_end;
 
 extern unsigned long socfpga_cpu1start_addr;
 
-#define SOCFPGA_SCU_VIRT_BASE   0xfffec000
+#define SOCFPGA_SCU_VIRT_BASE   0xfee00000
 
 #endif
index 383d61e..f5e597c 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/cacheflush.h>
 
 #include "core.h"
 
@@ -73,6 +74,10 @@ void __init socfpga_sysmgr_init(void)
                        (u32 *) &socfpga_cpu1start_addr))
                pr_err("SMP: Need cpu1-start-addr in device tree.\n");
 
+       /* Ensure that socfpga_cpu1start_addr is visible to other CPUs */
+       smp_wmb();
+       sync_cache_w(&socfpga_cpu1start_addr);
+
        sys_manager_base_addr = of_iomap(np, 0);
 
        np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
index b067390..b373aca 100644 (file)
@@ -18,6 +18,7 @@ static const char *stih41x_dt_match[] __initdata = {
        "st,stih415",
        "st,stih416",
        "st,stih407",
+       "st,stih410",
        "st,stih418",
        NULL
 };
index a77604f..81502b9 100644 (file)
@@ -1,10 +1,12 @@
 menuconfig ARCH_SUNXI
        bool "Allwinner SoCs" if ARCH_MULTI_V7
        select ARCH_REQUIRE_GPIOLIB
+       select ARCH_HAS_RESET_CONTROLLER
        select CLKSRC_MMIO
        select GENERIC_IRQ_CHIP
        select PINCTRL
        select SUN4I_TIMER
+       select RESET_CONTROLLER
 
 if ARCH_SUNXI
 
@@ -20,10 +22,8 @@ config MACH_SUN5I
 config MACH_SUN6I
        bool "Allwinner A31 (sun6i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select MFD_SUN6I_PRCM
-       select RESET_CONTROLLER
        select SUN5I_HSTIMER
 
 config MACH_SUN7I
@@ -37,16 +37,12 @@ config MACH_SUN7I
 config MACH_SUN8I
        bool "Allwinner A23 (sun8i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select MFD_SUN6I_PRCM
-       select RESET_CONTROLLER
 
 config MACH_SUN9I
        bool "Allwinner (sun9i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
-       select RESET_CONTROLLER
 
 endif
index c6c7696..8f15f70 100644 (file)
@@ -1131,23 +1131,22 @@ static void __init l2c310_of_parse(const struct device_node *np,
        }
 
        ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K);
-       if (ret)
-               return;
-
-       switch (assoc) {
-       case 16:
-               *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
-               *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               break;
-       case 8:
-               *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               break;
-       default:
-               pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
-                      assoc);
-               break;
+       if (!ret) {
+               switch (assoc) {
+               case 16:
+                       *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
+                       *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       break;
+               case 8:
+                       *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       break;
+               default:
+                       pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
+                              assoc);
+                       break;
+               }
        }
 
        prefetch = l2x0_saved_regs.prefetch_ctrl;
index 170a116..c274476 100644 (file)
@@ -171,7 +171,7 @@ static int __dma_supported(struct device *dev, u64 mask, bool warn)
         */
        if (sizeof(mask) != sizeof(dma_addr_t) &&
            mask > (dma_addr_t)~0 &&
-           dma_to_pfn(dev, ~0) < max_pfn) {
+           dma_to_pfn(dev, ~0) < max_pfn - 1) {
                if (warn) {
                        dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
                                 mask);
index a982dc3..6333d9c 100644 (file)
@@ -552,6 +552,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 
        pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
                inf->name, fsr, addr);
+       show_pte(current->mm, addr);
 
        info.si_signo = inf->sig;
        info.si_errno = 0;
index 004e35c..cf30daf 100644 (file)
@@ -49,7 +49,10 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (!is_module_address(start) || !is_module_address(end - 1))
+       if (start < MODULES_VADDR || start >= MODULES_END)
+               return -EINVAL;
+
+       if (end < MODULES_VADDR || start >= MODULES_END)
                return -EINVAL;
 
        data.set_mask = set_mask;
index db10169..8ca94d3 100644 (file)
@@ -799,6 +799,7 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const struct of_device_id *match;
        const struct dmtimer_platform_data *pdata;
+       int ret;
 
        match = of_match_device(of_match_ptr(omap_timer_match), dev);
        pdata = match ? match->data : dev->platform_data;
@@ -860,7 +861,12 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        }
 
        if (!timer->reserved) {
-               pm_runtime_get_sync(dev);
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0) {
+                       dev_err(dev, "%s: pm_runtime_get_sync failed!\n",
+                               __func__);
+                       goto err_get_sync;
+               }
                __omap_dm_timer_init_regs(timer);
                pm_runtime_put(dev);
        }
@@ -873,6 +879,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        dev_dbg(dev, "Device Probed.\n");
 
        return 0;
+
+err_get_sync:
+       pm_runtime_put_noidle(dev);
+       pm_runtime_disable(dev);
+       return ret;
 }
 
 /**
@@ -899,6 +910,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
                }
        spin_unlock_irqrestore(&dm_timer_lock, flags);
 
+       pm_runtime_disable(&pdev->dev);
+
        return ret;
 }
 
index f1ad9c2..a857794 100644 (file)
                };
 
                sgenet0: ethernet@1f210000 {
-                       compatible = "apm,xgene-enet";
+                       compatible = "apm,xgene1-sgenet";
                        status = "disabled";
                        reg = <0x0 0x1f210000 0x0 0xd100>,
                              <0x0 0x1f200000 0x0 0Xc300>,
                };
 
                xgenet: ethernet@1f610000 {
-                       compatible = "apm,xgene-enet";
+                       compatible = "apm,xgene1-xgenet";
                        status = "disabled";
                        reg = <0x0 0x1f610000 0x0 0xd100>,
                              <0x0 0x1f600000 0x0 0Xc300>,
index 27f3296..4eac8dc 100644 (file)
@@ -34,6 +34,7 @@
                        reg = <0x0 0x0>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@1 {
                        device_type = "cpu";
@@ -41,6 +42,7 @@
                        reg = <0x0 0x1>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@2 {
                        device_type = "cpu";
@@ -48,6 +50,7 @@
                        reg = <0x0 0x2>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@3 {
                        device_type = "cpu";
                        reg = <0x0 0x3>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
                };
        };
 
index ea2b566..c9b89ef 100644 (file)
@@ -8,7 +8,7 @@
  */
 
        /* SoC fixed clocks */
-       soc_uartclk: refclk72738khz {
+       soc_uartclk: refclk7273800hz {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <7273800>;
index d429129..133ee59 100644 (file)
@@ -39,6 +39,7 @@
                        reg = <0x0 0x0>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A57_L2>;
                };
 
                A57_1: cpu@1 {
@@ -46,6 +47,7 @@
                        reg = <0x0 0x1>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A57_L2>;
                };
 
                A53_0: cpu@100 {
@@ -53,6 +55,7 @@
                        reg = <0x0 0x100>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_1: cpu@101 {
@@ -60,6 +63,7 @@
                        reg = <0x0 0x101>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_2: cpu@102 {
@@ -67,6 +71,7 @@
                        reg = <0x0 0x102>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_3: cpu@103 {
                        reg = <0x0 0x103>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
+               };
+
+               A57_L2: l2-cache0 {
+                       compatible = "cache";
+               };
+
+               A53_L2: l2-cache1 {
+                       compatible = "cache";
                };
        };
 
index efc59b3..20addab 100644 (file)
@@ -37,6 +37,7 @@
                        reg = <0x0 0x0>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@1 {
                        device_type = "cpu";
@@ -44,6 +45,7 @@
                        reg = <0x0 0x1>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@2 {
                        device_type = "cpu";
@@ -51,6 +53,7 @@
                        reg = <0x0 0x2>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@3 {
                        device_type = "cpu";
                        reg = <0x0 0x3>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
                };
        };
 
index 5720608..abb79b3 100644 (file)
@@ -29,7 +29,7 @@ aes-ce-blk-y := aes-glue-ce.o aes-ce.o
 obj-$(CONFIG_CRYPTO_AES_ARM64_NEON_BLK) += aes-neon-blk.o
 aes-neon-blk-y := aes-glue-neon.o aes-neon.o
 
-AFLAGS_aes-ce.o                := -DINTERLEAVE=2 -DINTERLEAVE_INLINE
+AFLAGS_aes-ce.o                := -DINTERLEAVE=4
 AFLAGS_aes-neon.o      := -DINTERLEAVE=4
 
 CFLAGS_aes-glue-ce.o   := -DUSE_V8_CRYPTO_EXTENSIONS
index 5901480..750bac4 100644 (file)
@@ -20,6 +20,9 @@
 #error "Only include this from assembly code"
 #endif
 
+#ifndef __ASM_ASSEMBLER_H
+#define __ASM_ASSEMBLER_H
+
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 
@@ -155,3 +158,5 @@ lr  .req    x30             // link register
 #endif
        orr     \rd, \lbits, \hbits, lsl #32
        .endm
+
+#endif /* __ASM_ASSEMBLER_H */
index cb95930..d8c25b7 100644 (file)
@@ -246,14 +246,30 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
        __ret; \
 })
 
-#define this_cpu_cmpxchg_1(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_2(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_4(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_8(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-
-#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
-       cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \
-                               o1, o2, n1, n2)
+#define _protect_cmpxchg_local(pcp, o, n)                      \
+({                                                             \
+       typeof(*raw_cpu_ptr(&(pcp))) __ret;                     \
+       preempt_disable();                                      \
+       __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n);       \
+       preempt_enable();                                       \
+       __ret;                                                  \
+})
+
+#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+
+#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2)          \
+({                                                                     \
+       int __ret;                                                      \
+       preempt_disable();                                              \
+       __ret = cmpxchg_double_local(   raw_cpu_ptr(&(ptr1)),           \
+                                       raw_cpu_ptr(&(ptr2)),           \
+                                       o1, o2, n1, n2);                \
+       preempt_enable();                                               \
+       __ret;                                                          \
+})
 
 #define cmpxchg64(ptr,o,n)             cmpxchg((ptr),(o),(n))
 #define cmpxchg64_local(ptr,o,n)       cmpxchg_local((ptr),(o),(n))
index 0710654..c60643f 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_CPUIDLE_H
 #define __ASM_CPUIDLE_H
 
+#include <asm/proc-fns.h>
+
 #ifdef CONFIG_CPU_IDLE
 extern int cpu_init_idle(unsigned int cpu);
 extern int cpu_suspend(unsigned long arg);
index e2ff32a..d2f4942 100644 (file)
@@ -264,8 +264,10 @@ __AARCH64_INSN_FUNCS(ands, 0x7F200000, 0x6A000000)
 __AARCH64_INSN_FUNCS(bics,     0x7F200000, 0x6A200000)
 __AARCH64_INSN_FUNCS(b,                0xFC000000, 0x14000000)
 __AARCH64_INSN_FUNCS(bl,       0xFC000000, 0x94000000)
-__AARCH64_INSN_FUNCS(cbz,      0xFE000000, 0x34000000)
-__AARCH64_INSN_FUNCS(cbnz,     0xFE000000, 0x35000000)
+__AARCH64_INSN_FUNCS(cbz,      0x7F000000, 0x34000000)
+__AARCH64_INSN_FUNCS(cbnz,     0x7F000000, 0x35000000)
+__AARCH64_INSN_FUNCS(tbz,      0x7F000000, 0x36000000)
+__AARCH64_INSN_FUNCS(tbnz,     0x7F000000, 0x37000000)
 __AARCH64_INSN_FUNCS(bcond,    0xFF000010, 0x54000000)
 __AARCH64_INSN_FUNCS(svc,      0xFFE0001F, 0xD4000001)
 __AARCH64_INSN_FUNCS(hvc,      0xFFE0001F, 0xD4000002)
index 94674eb..54bb4ba 100644 (file)
  * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
  * not known to exist and will break with this configuration.
  *
+ * VTCR_EL2.PS is extracted from ID_AA64MMFR0_EL1.PARange at boot time
+ * (see hyp-init.S).
+ *
  * Note that when using 4K pages, we concatenate two first level page tables
  * together.
  *
 #ifdef CONFIG_ARM64_64K_PAGES
 /*
  * Stage2 translation configuration:
- * 40bits output (PS = 2)
  * 40bits input  (T0SZ = 24)
  * 64kB pages (TG0 = 1)
  * 2 level page tables (SL = 1)
 #else
 /*
  * Stage2 translation configuration:
- * 40bits output (PS = 2)
  * 40bits input  (T0SZ = 24)
  * 4kB pages (TG0 = 0)
  * 3 level page tables (SL = 1)
index 6458b53..bbfb600 100644 (file)
@@ -158,6 +158,8 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define PTRS_PER_S2_PGD                (1 << PTRS_PER_S2_PGD_SHIFT)
 #define S2_PGD_ORDER           get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
 
+#define kvm_pgd_index(addr)    (((addr) >> PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1))
+
 /*
  * If we are concatenating first level stage-2 page tables, we would have less
  * than or equal to 16 pointers in the fake PGD, because that's what the
@@ -171,43 +173,6 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define KVM_PREALLOC_LEVEL     (0)
 #endif
 
-/**
- * kvm_prealloc_hwpgd - allocate inital table for VTTBR
- * @kvm:       The KVM struct pointer for the VM.
- * @pgd:       The kernel pseudo pgd
- *
- * When the kernel uses more levels of page tables than the guest, we allocate
- * a fake PGD and pre-populate it to point to the next-level page table, which
- * will be the real initial page table pointed to by the VTTBR.
- *
- * When KVM_PREALLOC_LEVEL==2, we allocate a single page for the PMD and
- * the kernel will use folded pud.  When KVM_PREALLOC_LEVEL==1, we
- * allocate 2 consecutive PUD pages.
- */
-static inline int kvm_prealloc_hwpgd(struct kvm *kvm, pgd_t *pgd)
-{
-       unsigned int i;
-       unsigned long hwpgd;
-
-       if (KVM_PREALLOC_LEVEL == 0)
-               return 0;
-
-       hwpgd = __get_free_pages(GFP_KERNEL | __GFP_ZERO, PTRS_PER_S2_PGD_SHIFT);
-       if (!hwpgd)
-               return -ENOMEM;
-
-       for (i = 0; i < PTRS_PER_S2_PGD; i++) {
-               if (KVM_PREALLOC_LEVEL == 1)
-                       pgd_populate(NULL, pgd + i,
-                                    (pud_t *)hwpgd + i * PTRS_PER_PUD);
-               else if (KVM_PREALLOC_LEVEL == 2)
-                       pud_populate(NULL, pud_offset(pgd, 0) + i,
-                                    (pmd_t *)hwpgd + i * PTRS_PER_PMD);
-       }
-
-       return 0;
-}
-
 static inline void *kvm_get_hwpgd(struct kvm *kvm)
 {
        pgd_t *pgd = kvm->arch.pgd;
@@ -224,12 +189,11 @@ static inline void *kvm_get_hwpgd(struct kvm *kvm)
        return pmd_offset(pud, 0);
 }
 
-static inline void kvm_free_hwpgd(struct kvm *kvm)
+static inline unsigned int kvm_get_hwpgd_size(void)
 {
-       if (KVM_PREALLOC_LEVEL > 0) {
-               unsigned long hwpgd = (unsigned long)kvm_get_hwpgd(kvm);
-               free_pages(hwpgd, PTRS_PER_S2_PGD_SHIFT);
-       }
+       if (KVM_PREALLOC_LEVEL > 0)
+               return PTRS_PER_S2_PGD * PAGE_SIZE;
+       return PTRS_PER_S2_PGD * sizeof(pgd_t);
 }
 
 static inline bool kvm_page_empty(void *ptr)
index a9eee33..101a42b 100644 (file)
@@ -151,6 +151,15 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        unsigned int cpu = smp_processor_id();
 
+       /*
+        * init_mm.pgd does not contain any user mappings and it is always
+        * active for kernel addresses in TTBR1. Just set the reserved TTBR0.
+        */
+       if (next == &init_mm) {
+               cpu_set_reserved_ttbr0();
+               return;
+       }
+
        if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
                check_and_switch_context(next, tsk);
 }
index 09da25b..4fde8c1 100644 (file)
@@ -204,25 +204,47 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
        return ret;
 }
 
+#define _percpu_read(pcp)                                              \
+({                                                                     \
+       typeof(pcp) __retval;                                           \
+       preempt_disable();                                              \
+       __retval = (typeof(pcp))__percpu_read(raw_cpu_ptr(&(pcp)),      \
+                                             sizeof(pcp));             \
+       preempt_enable();                                               \
+       __retval;                                                       \
+})
+
+#define _percpu_write(pcp, val)                                                \
+do {                                                                   \
+       preempt_disable();                                              \
+       __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val),       \
+                               sizeof(pcp));                           \
+       preempt_enable();                                               \
+} while(0)                                                             \
+
+#define _pcp_protect(operation, pcp, val)                      \
+({                                                             \
+       typeof(pcp) __retval;                                   \
+       preempt_disable();                                      \
+       __retval = (typeof(pcp))operation(raw_cpu_ptr(&(pcp)),  \
+                                         (val), sizeof(pcp));  \
+       preempt_enable();                                       \
+       __retval;                                               \
+})
+
 #define _percpu_add(pcp, val) \
-       __percpu_add(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+       _pcp_protect(__percpu_add, pcp, val)
 
-#define _percpu_add_return(pcp, val) (typeof(pcp)) (_percpu_add(pcp, val))
+#define _percpu_add_return(pcp, val) _percpu_add(pcp, val)
 
 #define _percpu_and(pcp, val) \
-       __percpu_and(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+       _pcp_protect(__percpu_and, pcp, val)
 
 #define _percpu_or(pcp, val) \
-       __percpu_or(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
-
-#define _percpu_read(pcp) (typeof(pcp))        \
-       (__percpu_read(raw_cpu_ptr(&(pcp)), sizeof(pcp)))
-
-#define _percpu_write(pcp, val) \
-       __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp))
+       _pcp_protect(__percpu_or, pcp, val)
 
 #define _percpu_xchg(pcp, val) (typeof(pcp)) \
-       (__percpu_xchg(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp)))
+       _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val))
 
 #define this_cpu_add_1(pcp, val) _percpu_add(pcp, val)
 #define this_cpu_add_2(pcp, val) _percpu_add(pcp, val)
index 16449c5..800ec0e 100644 (file)
@@ -460,7 +460,7 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
-                             PTE_PROT_NONE | PTE_VALID | PTE_WRITE;
+                             PTE_PROT_NONE | PTE_WRITE | PTE_TYPE_MASK;
        pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
        return pte;
 }
index 9a8fd84..941c375 100644 (file)
@@ -39,7 +39,11 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
 
 #include <asm/memory.h>
 
-#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
+#define cpu_switch_mm(pgd,mm)                          \
+do {                                                   \
+       BUG_ON(pgd == swapper_pg_dir);                  \
+       cpu_do_switch_mm(virt_to_phys(pgd),mm);         \
+} while (0)
 
 #define cpu_get_pgd()                                  \
 ({                                                     \
index f9be30e..20e9591 100644 (file)
@@ -45,7 +45,8 @@
 #define STACK_TOP              STACK_TOP_MAX
 #endif /* CONFIG_COMPAT */
 
-#define ARCH_LOW_ADDRESS_LIMIT PHYS_MASK
+extern phys_addr_t arm64_dma_phys_limit;
+#define ARCH_LOW_ADDRESS_LIMIT (arm64_dma_phys_limit - 1)
 #endif /* __KERNEL__ */
 
 struct debug_info {
index c028fe3..53d9c35 100644 (file)
@@ -48,6 +48,7 @@ static inline void tlb_flush(struct mmu_gather *tlb)
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        pgtable_page_dtor(pte);
        tlb_remove_entry(tlb, pte);
 }
@@ -56,6 +57,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
 static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        tlb_remove_entry(tlb, virt_to_page(pmdp));
 }
 #endif
@@ -64,6 +66,7 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
 static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        tlb_remove_entry(tlb, virt_to_page(pudp));
 }
 #endif
index 73f0ce5..c3bb05b 100644 (file)
 #include <linux/sched.h>
 #include <asm/cputype.h>
 
-extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
-extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
-
-extern struct cpu_tlb_fns cpu_tlb;
-
 /*
  *     TLB Management
  *     ==============
@@ -148,6 +143,19 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
                flush_tlb_all();
 }
 
+/*
+ * Used to invalidate the TLB (walk caches) corresponding to intermediate page
+ * table levels (pgd/pud/pmd).
+ */
+static inline void __flush_tlb_pgtable(struct mm_struct *mm,
+                                      unsigned long uaddr)
+{
+       unsigned long addr = uaddr >> 12 | ((unsigned long)ASID(mm) << 48);
+
+       dsb(ishst);
+       asm("tlbi       vae1is, %0" : : "r" (addr));
+       dsb(ish);
+}
 /*
  * On AArch64, the cache coherency is handled via the set_pte_at() function.
  */
index bef04af..5ee07ee 100644 (file)
@@ -15,8 +15,9 @@ CFLAGS_REMOVE_return_address.o = -pg
 arm64-obj-y            := cputable.o debug-monitors.o entry.o irq.o fpsimd.o   \
                           entry-fpsimd.o process.o ptrace.o setup.o signal.o   \
                           sys.o stacktrace.o time.o traps.o io.o vdso.o        \
-                          hyp-stub.o psci.o cpu_ops.o insn.o return_address.o  \
-                          cpuinfo.o cpu_errata.o alternative.o cacheinfo.o
+                          hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o       \
+                          return_address.o cpuinfo.o cpu_errata.o              \
+                          alternative.o cacheinfo.o
 
 arm64-obj-$(CONFIG_COMPAT)             += sys32.o kuser32.o signal32.o         \
                                           sys_compat.o entry32.o               \
index b42c7b4..ab21e0d 100644 (file)
@@ -337,7 +337,11 @@ core_initcall(arm64_dmi_init);
 
 static void efi_set_pgd(struct mm_struct *mm)
 {
-       cpu_switch_mm(mm->pgd, mm);
+       if (mm == &init_mm)
+               cpu_set_reserved_ttbr0();
+       else
+               cpu_switch_mm(mm->pgd, mm);
+
        flush_tlb_all();
        if (icache_is_aivivt())
                __flush_icache_all();
@@ -354,3 +358,12 @@ void efi_virtmap_unload(void)
        efi_set_pgd(current->active_mm);
        preempt_enable();
 }
+
+/*
+ * UpdateCapsule() depends on the system being shutdown via
+ * ResetSystem().
+ */
+bool efi_poweroff_required(void)
+{
+       return efi_enabled(EFI_RUNTIME_SERVICES);
+}
index cf8556a..c851be7 100644 (file)
@@ -156,7 +156,7 @@ static int ftrace_modify_graph_caller(bool enable)
 
        branch = aarch64_insn_gen_branch_imm(pc,
                                             (unsigned long)ftrace_graph_caller,
-                                            AARCH64_INSN_BRANCH_LINK);
+                                            AARCH64_INSN_BRANCH_NOLINK);
        nop = aarch64_insn_gen_nop();
 
        if (enable)
index 8ce88e0..07f9305 100644 (file)
@@ -585,8 +585,8 @@ ENDPROC(set_cpu_boot_mode_flag)
  * zeroing of .bss would clobber it.
  */
        .pushsection    .data..cacheline_aligned
-ENTRY(__boot_cpu_mode)
        .align  L1_CACHE_SHIFT
+ENTRY(__boot_cpu_mode)
        .long   BOOT_CPU_MODE_EL2
        .long   0
        .popsection
index 27d4864..c8eca88 100644 (file)
@@ -87,8 +87,10 @@ static void __kprobes *patch_map(void *addr, int fixmap)
 
        if (module && IS_ENABLED(CONFIG_DEBUG_SET_MODULE_RONX))
                page = vmalloc_to_page(addr);
-       else
+       else if (!module && IS_ENABLED(CONFIG_DEBUG_RODATA))
                page = virt_to_page(addr);
+       else
+               return addr;
 
        BUG_ON(!page);
        set_fixmap(fixmap, page_to_phys(page));
index fde9923..c6b1f3b 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdarg.h>
 
 #include <linux/compat.h>
+#include <linux/efi.h>
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -150,6 +151,13 @@ void machine_restart(char *cmd)
        local_irq_disable();
        smp_send_stop();
 
+       /*
+        * UpdateCapsule() depends on the system being reset via
+        * ResetSystem().
+        */
+       if (efi_enabled(EFI_RUNTIME_SERVICES))
+               efi_reboot(reboot_mode, NULL);
+
        /* Now call the architecture specific reboot code. */
        if (arm_pm_restart)
                arm_pm_restart(reboot_mode, cmd);
diff --git a/arch/arm64/kernel/psci-call.S b/arch/arm64/kernel/psci-call.S
new file mode 100644 (file)
index 0000000..cf83e61
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/linkage.h>
+
+/* int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
+ENTRY(__invoke_psci_fn_hvc)
+       hvc     #0
+       ret
+ENDPROC(__invoke_psci_fn_hvc)
+
+/* int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
+ENTRY(__invoke_psci_fn_smc)
+       smc     #0
+       ret
+ENDPROC(__invoke_psci_fn_smc)
index 3425f31..9b8a70a 100644 (file)
@@ -57,6 +57,9 @@ static struct psci_operations psci_ops;
 static int (*invoke_psci_fn)(u64, u64, u64, u64);
 typedef int (*psci_initcall_t)(const struct device_node *);
 
+asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64);
+asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64);
+
 enum psci_function {
        PSCI_FN_CPU_SUSPEND,
        PSCI_FN_CPU_ON,
@@ -109,40 +112,6 @@ static void psci_power_state_unpack(u32 power_state,
                        PSCI_0_2_POWER_STATE_AFFL_SHIFT;
 }
 
-/*
- * The following two functions are invoked via the invoke_psci_fn pointer
- * and will not be inlined, allowing us to piggyback on the AAPCS.
- */
-static noinline int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1,
-                                        u64 arg2)
-{
-       asm volatile(
-                       __asmeq("%0", "x0")
-                       __asmeq("%1", "x1")
-                       __asmeq("%2", "x2")
-                       __asmeq("%3", "x3")
-                       "hvc    #0\n"
-               : "+r" (function_id)
-               : "r" (arg0), "r" (arg1), "r" (arg2));
-
-       return function_id;
-}
-
-static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
-                                        u64 arg2)
-{
-       asm volatile(
-                       __asmeq("%0", "x0")
-                       __asmeq("%1", "x1")
-                       __asmeq("%2", "x2")
-                       __asmeq("%3", "x3")
-                       "smc    #0\n"
-               : "+r" (function_id)
-               : "r" (arg0), "r" (arg1), "r" (arg2));
-
-       return function_id;
-}
-
 static int psci_get_version(void)
 {
        int err;
index c20a300..d26fcd4 100644 (file)
@@ -154,8 +154,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
        case __SI_TIMER:
                 err |= __put_user(from->si_tid, &to->si_tid);
                 err |= __put_user(from->si_overrun, &to->si_overrun);
-                err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr,
-                                  &to->si_ptr);
+                err |= __put_user(from->si_int, &to->si_int);
                break;
        case __SI_POLL:
                err |= __put_user(from->si_band, &to->si_band);
@@ -184,7 +183,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
        case __SI_MESGQ: /* But this is */
                err |= __put_user(from->si_pid, &to->si_pid);
                err |= __put_user(from->si_uid, &to->si_uid);
-               err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr);
+               err |= __put_user(from->si_int, &to->si_int);
                break;
        case __SI_SYS:
                err |= __put_user((compat_uptr_t)(unsigned long)
index fe652ff..efa79e8 100644 (file)
@@ -174,8 +174,6 @@ ENDPROC(__kernel_clock_gettime)
 /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
 ENTRY(__kernel_clock_getres)
        .cfi_startproc
-       cbz     w1, 3f
-
        cmp     w0, #CLOCK_REALTIME
        ccmp    w0, #CLOCK_MONOTONIC, #0x4, ne
        b.ne    1f
@@ -188,6 +186,7 @@ ENTRY(__kernel_clock_getres)
        b.ne    4f
        ldr     x2, 6f
 2:
+       cbz     w1, 3f
        stp     xzr, x2, [x1]
 
 3:     /* res == NULL. */
index 0a24b9b..ef7d112 100644 (file)
@@ -51,7 +51,7 @@ static int __init early_coherent_pool(char *p)
 }
 early_param("coherent_pool", early_coherent_pool);
 
-static void *__alloc_from_pool(size_t size, struct page **ret_page)
+static void *__alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
 {
        unsigned long val;
        void *ptr = NULL;
@@ -67,6 +67,8 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
 
                *ret_page = phys_to_page(phys);
                ptr = (void *)val;
+               if (flags & __GFP_ZERO)
+                       memset(ptr, 0, size);
        }
 
        return ptr;
@@ -101,6 +103,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                flags |= GFP_DMA;
        if (IS_ENABLED(CONFIG_DMA_CMA) && (flags & __GFP_WAIT)) {
                struct page *page;
+               void *addr;
 
                size = PAGE_ALIGN(size);
                page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
@@ -109,7 +112,10 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                        return NULL;
 
                *dma_handle = phys_to_dma(dev, page_to_phys(page));
-               return page_address(page);
+               addr = page_address(page);
+               if (flags & __GFP_ZERO)
+                       memset(addr, 0, size);
+               return addr;
        } else {
                return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
        }
@@ -146,7 +152,7 @@ static void *__dma_alloc(struct device *dev, size_t size,
 
        if (!coherent && !(flags & __GFP_WAIT)) {
                struct page *page = NULL;
-               void *addr = __alloc_from_pool(size, &page);
+               void *addr = __alloc_from_pool(size, &page, flags);
 
                if (addr)
                        *dma_handle = phys_to_dma(dev, page_to_phys(page));
@@ -348,8 +354,6 @@ static struct dma_map_ops swiotlb_dma_ops = {
        .mapping_error = swiotlb_dma_mapping_error,
 };
 
-extern int swiotlb_late_init_with_default_size(size_t default_size);
-
 static int __init atomic_pool_init(void)
 {
        pgprot_t prot = __pgprot(PROT_NORMAL_NC);
@@ -411,21 +415,13 @@ out:
        return -ENOMEM;
 }
 
-static int __init swiotlb_late_init(void)
+static int __init arm64_dma_init(void)
 {
-       size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
+       int ret;
 
        dma_ops = &swiotlb_dma_ops;
 
-       return swiotlb_late_init_with_default_size(swiotlb_size);
-}
-
-static int __init arm64_dma_init(void)
-{
-       int ret = 0;
-
-       ret |= swiotlb_late_init();
-       ret |= atomic_pool_init();
+       ret = atomic_pool_init();
 
        return ret;
 }
index 71145f9..ae85da6 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dma-contiguous.h>
 #include <linux/efi.h>
+#include <linux/swiotlb.h>
 
 #include <asm/fixmap.h>
 #include <asm/memory.h>
@@ -45,6 +46,7 @@
 #include "mm.h"
 
 phys_addr_t memstart_addr __read_mostly = 0;
+phys_addr_t arm64_dma_phys_limit __read_mostly;
 
 #ifdef CONFIG_BLK_DEV_INITRD
 static int __init early_initrd(char *p)
@@ -85,7 +87,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 
        /* 4GB maximum for 32-bit only capable devices */
        if (IS_ENABLED(CONFIG_ZONE_DMA)) {
-               max_dma = PFN_DOWN(max_zone_dma_phys());
+               max_dma = PFN_DOWN(arm64_dma_phys_limit);
                zone_size[ZONE_DMA] = max_dma - min;
        }
        zone_size[ZONE_NORMAL] = max - max_dma;
@@ -156,8 +158,6 @@ early_param("mem", early_mem);
 
 void __init arm64_memblock_init(void)
 {
-       phys_addr_t dma_phys_limit = 0;
-
        memblock_enforce_memory_limit(memory_limit);
 
        /*
@@ -174,8 +174,10 @@ void __init arm64_memblock_init(void)
 
        /* 4GB maximum for 32-bit only capable devices */
        if (IS_ENABLED(CONFIG_ZONE_DMA))
-               dma_phys_limit = max_zone_dma_phys();
-       dma_contiguous_reserve(dma_phys_limit);
+               arm64_dma_phys_limit = max_zone_dma_phys();
+       else
+               arm64_dma_phys_limit = PHYS_MASK + 1;
+       dma_contiguous_reserve(arm64_dma_phys_limit);
 
        memblock_allow_resize();
        memblock_dump_all();
@@ -276,6 +278,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       swiotlb_init(1);
+
        set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
index bb0ea94..1d3ec3d 100644 (file)
@@ -51,7 +51,10 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (!is_module_address(start) || !is_module_address(end - 1))
+       if (start < MODULES_VADDR || start >= MODULES_END)
+               return -EINVAL;
+
+       if (end < MODULES_VADDR || end >= MODULES_END)
                return -EINVAL;
 
        data.set_mask = set_mask;
index 78d4483..ec4db6d 100644 (file)
@@ -67,6 +67,11 @@ extern unsigned long empty_zero_page;
  */
 #define pgtable_cache_init()   do { } while (0)
 
+/*
+ * c6x is !MMU, so define the simpliest implementation
+ */
+#define pgprot_writecombine pgprot_noncached
+
 #include <asm-generic/pgtable.h>
 
 #endif /* _ASM_C6X_PGTABLE_H */
index 93bcf2a..07d7a7e 100644 (file)
@@ -123,12 +123,14 @@ extern unsigned long empty_zero_page;
 #define PGDIR_MASK             (~(PGDIR_SIZE - 1))
 #define PTRS_PER_PGD           64
 
+#define __PAGETABLE_PUD_FOLDED
 #define PUD_SHIFT              26
 #define PTRS_PER_PUD           1
 #define PUD_SIZE               (1UL << PUD_SHIFT)
 #define PUD_MASK               (~(PUD_SIZE - 1))
 #define PUE_SIZE               256
 
+#define __PAGETABLE_PMD_FOLDED
 #define PMD_SHIFT              26
 #define PMD_SIZE               (1UL << PMD_SHIFT)
 #define PMD_MASK               (~(PMD_SIZE - 1))
index 8fd8ee7..421e6ba 100644 (file)
@@ -13,6 +13,7 @@
  * the M32R is two-level, so we don't really have any
  * PMD directory physically.
  */
+#define __PAGETABLE_PMD_FOLDED
 #define PMD_SHIFT      22
 #define PTRS_PER_PMD   1
 
index 28a145b..35ed4a9 100644 (file)
  */
 #ifdef CONFIG_SUN3
 #define PTRS_PER_PTE   16
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   2048
 #elif defined(CONFIG_COLDFIRE)
 #define PTRS_PER_PTE   512
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   1024
 #else
index 9359e50..d5779b0 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_METAG_IO_H
 
 #include <linux/types.h>
+#include <asm/pgtable-bits.h>
 
 #define IO_SPACE_LIMIT  0
 
diff --git a/arch/metag/include/asm/pgtable-bits.h b/arch/metag/include/asm/pgtable-bits.h
new file mode 100644 (file)
index 0000000..25ba672
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Meta page table definitions.
+ */
+
+#ifndef _METAG_PGTABLE_BITS_H
+#define _METAG_PGTABLE_BITS_H
+
+#include <asm/metag_mem.h>
+
+/*
+ * Definitions for MMU descriptors
+ *
+ * These are the hardware bits in the MMCU pte entries.
+ * Derived from the Meta toolkit headers.
+ */
+#define _PAGE_PRESENT          MMCU_ENTRY_VAL_BIT
+#define _PAGE_WRITE            MMCU_ENTRY_WR_BIT
+#define _PAGE_PRIV             MMCU_ENTRY_PRIV_BIT
+/* Write combine bit - this can cause writes to occur out of order */
+#define _PAGE_WR_COMBINE       MMCU_ENTRY_WRC_BIT
+/* Sys coherent bit - this bit is never used by Linux */
+#define _PAGE_SYS_COHERENT     MMCU_ENTRY_SYS_BIT
+#define _PAGE_ALWAYS_ZERO_1    0x020
+#define _PAGE_CACHE_CTRL0      0x040
+#define _PAGE_CACHE_CTRL1      0x080
+#define _PAGE_ALWAYS_ZERO_2    0x100
+#define _PAGE_ALWAYS_ZERO_3    0x200
+#define _PAGE_ALWAYS_ZERO_4    0x400
+#define _PAGE_ALWAYS_ZERO_5    0x800
+
+/* These are software bits that we stuff into the gaps in the hardware
+ * pte entries that are not used.  Note, these DO get stored in the actual
+ * hardware, but the hardware just does not use them.
+ */
+#define _PAGE_ACCESSED         _PAGE_ALWAYS_ZERO_1
+#define _PAGE_DIRTY            _PAGE_ALWAYS_ZERO_2
+
+/* Pages owned, and protected by, the kernel. */
+#define _PAGE_KERNEL           _PAGE_PRIV
+
+/* No cacheing of this page */
+#define _PAGE_CACHE_WIN0       (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S)
+/* burst cacheing - good for data streaming */
+#define _PAGE_CACHE_WIN1       (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S)
+/* One cache way per thread */
+#define _PAGE_CACHE_WIN2       (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S)
+/* Full on cacheing */
+#define _PAGE_CACHE_WIN3       (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S)
+
+#define _PAGE_CACHEABLE                (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE)
+
+/* which bits are used for cache control ... */
+#define _PAGE_CACHE_MASK       (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \
+                                _PAGE_WR_COMBINE)
+
+/* This is a mask of the bits that pte_modify is allowed to change. */
+#define _PAGE_CHG_MASK         (PAGE_MASK)
+
+#define _PAGE_SZ_SHIFT         1
+#define _PAGE_SZ_4K            (0x0)
+#define _PAGE_SZ_8K            (0x1 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_16K           (0x2 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_32K           (0x3 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_64K           (0x4 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_128K          (0x5 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_256K          (0x6 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_512K          (0x7 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_1M            (0x8 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_2M            (0x9 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_4M            (0xa << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_MASK          (0xf << _PAGE_SZ_SHIFT)
+
+#if defined(CONFIG_PAGE_SIZE_4K)
+#define _PAGE_SZ               (_PAGE_SZ_4K)
+#elif defined(CONFIG_PAGE_SIZE_8K)
+#define _PAGE_SZ               (_PAGE_SZ_8K)
+#elif defined(CONFIG_PAGE_SIZE_16K)
+#define _PAGE_SZ               (_PAGE_SZ_16K)
+#endif
+#define _PAGE_TABLE            (_PAGE_SZ | _PAGE_PRESENT)
+
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_8K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_16K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_32K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_64K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_128K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_256K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_512K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_1M)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_2M)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_4M)
+#endif
+
+#endif /* _METAG_PGTABLE_BITS_H */
index d0604c0..ffa3a3a 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef _METAG_PGTABLE_H
 #define _METAG_PGTABLE_H
 
+#include <asm/pgtable-bits.h>
 #include <asm-generic/pgtable-nopmd.h>
 
 /* Invalid regions on Meta: 0x00000000-0x001FFFFF and 0xFFFF0000-0xFFFFFFFF */
 #define VMALLOC_END            0x7FFFFFFF
 #endif
 
-/*
- * Definitions for MMU descriptors
- *
- * These are the hardware bits in the MMCU pte entries.
- * Derived from the Meta toolkit headers.
- */
-#define _PAGE_PRESENT          MMCU_ENTRY_VAL_BIT
-#define _PAGE_WRITE            MMCU_ENTRY_WR_BIT
-#define _PAGE_PRIV             MMCU_ENTRY_PRIV_BIT
-/* Write combine bit - this can cause writes to occur out of order */
-#define _PAGE_WR_COMBINE       MMCU_ENTRY_WRC_BIT
-/* Sys coherent bit - this bit is never used by Linux */
-#define _PAGE_SYS_COHERENT     MMCU_ENTRY_SYS_BIT
-#define _PAGE_ALWAYS_ZERO_1    0x020
-#define _PAGE_CACHE_CTRL0      0x040
-#define _PAGE_CACHE_CTRL1      0x080
-#define _PAGE_ALWAYS_ZERO_2    0x100
-#define _PAGE_ALWAYS_ZERO_3    0x200
-#define _PAGE_ALWAYS_ZERO_4    0x400
-#define _PAGE_ALWAYS_ZERO_5    0x800
-
-/* These are software bits that we stuff into the gaps in the hardware
- * pte entries that are not used.  Note, these DO get stored in the actual
- * hardware, but the hardware just does not use them.
- */
-#define _PAGE_ACCESSED         _PAGE_ALWAYS_ZERO_1
-#define _PAGE_DIRTY            _PAGE_ALWAYS_ZERO_2
-
-/* Pages owned, and protected by, the kernel. */
-#define _PAGE_KERNEL           _PAGE_PRIV
-
-/* No cacheing of this page */
-#define _PAGE_CACHE_WIN0       (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S)
-/* burst cacheing - good for data streaming */
-#define _PAGE_CACHE_WIN1       (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S)
-/* One cache way per thread */
-#define _PAGE_CACHE_WIN2       (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S)
-/* Full on cacheing */
-#define _PAGE_CACHE_WIN3       (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S)
-
-#define _PAGE_CACHEABLE                (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE)
-
-/* which bits are used for cache control ... */
-#define _PAGE_CACHE_MASK       (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \
-                                _PAGE_WR_COMBINE)
-
-/* This is a mask of the bits that pte_modify is allowed to change. */
-#define _PAGE_CHG_MASK         (PAGE_MASK)
-
-#define _PAGE_SZ_SHIFT         1
-#define _PAGE_SZ_4K            (0x0)
-#define _PAGE_SZ_8K            (0x1 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_16K           (0x2 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_32K           (0x3 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_64K           (0x4 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_128K          (0x5 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_256K          (0x6 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_512K          (0x7 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_1M            (0x8 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_2M            (0x9 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_4M            (0xa << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_MASK          (0xf << _PAGE_SZ_SHIFT)
-
-#if defined(CONFIG_PAGE_SIZE_4K)
-#define _PAGE_SZ               (_PAGE_SZ_4K)
-#elif defined(CONFIG_PAGE_SIZE_8K)
-#define _PAGE_SZ               (_PAGE_SZ_8K)
-#elif defined(CONFIG_PAGE_SIZE_16K)
-#define _PAGE_SZ               (_PAGE_SZ_16K)
-#endif
-#define _PAGE_TABLE            (_PAGE_SZ | _PAGE_PRESENT)
-
-#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_8K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_16K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_32K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_64K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_128K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_256K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_512K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_1M)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_2M)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_4M)
-#endif
-
 /*
  * The Linux memory management assumes a three-level page table setup. On
  * Meta, we use that, but "fold" the mid level into the top-level page
index 881071c..13272fd 100644 (file)
@@ -149,8 +149,8 @@ extern void exit_thread(void);
 
 unsigned long get_wchan(struct task_struct *p);
 
-#define        KSTK_EIP(tsk)   ((tsk)->thread.kernel_context->CurrPC)
-#define        KSTK_ESP(tsk)   ((tsk)->thread.kernel_context->AX[0].U0)
+#define        KSTK_EIP(tsk)   (task_pt_regs(tsk)->ctx.CurrPC)
+#define        KSTK_ESP(tsk)   (task_pt_regs(tsk)->ctx.AX[0].U0)
 
 #define user_stack_pointer(regs)        ((regs)->ctx.AX[0].U0)
 
index 0536bc0..ef54851 100644 (file)
@@ -348,8 +348,9 @@ C_ENTRY(_user_exception):
  * The LP register should point to the location where the called function
  * should return.  [note that MAKE_SYS_CALL uses label 1] */
        /* See if the system call number is valid */
+       blti    r12, 5f
        addi    r11, r12, -__NR_syscalls;
-       bgei    r11,5f;
+       bgei    r11, 5f;
        /* Figure out which function to use for this system call.  */
        /* Note Microblaze barrel shift is optional, so don't rely on it */
        add     r12, r12, r12;                  /* convert num -> ptr */
@@ -375,7 +376,7 @@ C_ENTRY(_user_exception):
 
        /* The syscall number is invalid, return an error.  */
 5:
-       rtsd    r15, 8;         /* looks like a normal subroutine return */
+       braid   ret_from_trap
        addi    r3, r0, -ENOSYS;
 
 /* Entry point used to return from a syscall/trap */
@@ -411,7 +412,7 @@ C_ENTRY(ret_from_trap):
        bri     1b
 
        /* Maybe handle a signal */
-5:     
+5:
        andi    r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
        beqi    r11, 4f;                /* Signals to handle, handle them */
 
index bbcd822..b6beb0e 100644 (file)
@@ -216,6 +216,7 @@ int kvm_mips_host_tlb_write(struct kvm_vcpu *vcpu, unsigned long entryhi,
        if (idx > current_cpu_data.tlbsize) {
                kvm_err("%s: Invalid Index: %d\n", __func__, idx);
                kvm_mips_dump_host_tlbs();
+               local_irq_restore(flags);
                return -1;
        }
 
index c1388d4..bd6437f 100644 (file)
@@ -24,18 +24,18 @@ TRACE_EVENT(kvm_exit,
            TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
            TP_ARGS(vcpu, reason),
            TP_STRUCT__entry(
-                       __field(struct kvm_vcpu *, vcpu)
+                       __field(unsigned long, pc)
                        __field(unsigned int, reason)
            ),
 
            TP_fast_assign(
-                       __entry->vcpu = vcpu;
+                       __entry->pc = vcpu->arch.pc;
                        __entry->reason = reason;
            ),
 
            TP_printk("[%s]PC: 0x%08lx",
                      kvm_mips_exit_types_str[__entry->reason],
-                     __entry->vcpu->arch.pc)
+                     __entry->pc)
 );
 
 #endif /* _TRACE_KVM_H */
index afab728..96d3f9d 100644 (file)
@@ -56,7 +56,9 @@ extern void paging_init(void);
 #define PGDIR_SHIFT    22
 #define PTRS_PER_PGD   1024
 #define PTRS_PER_PUD   1       /* we don't really have any PUD physically */
+#define __PAGETABLE_PUD_FOLDED
 #define PTRS_PER_PMD   1       /* we don't really have any PMD physically */
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PTE   1024
 
 #define PGD_SIZE       PAGE_SIZE
index 20fb1cf..6424621 100644 (file)
 
 #include <uapi/asm/ptrace.h>
 
+/* This struct defines the way the registers are stored on the
+   stack during a system call.  */
+
 #ifndef __ASSEMBLY__
+struct pt_regs {
+       unsigned long  r8;      /* r8-r15 Caller-saved GP registers */
+       unsigned long  r9;
+       unsigned long  r10;
+       unsigned long  r11;
+       unsigned long  r12;
+       unsigned long  r13;
+       unsigned long  r14;
+       unsigned long  r15;
+       unsigned long  r1;      /* Assembler temporary */
+       unsigned long  r2;      /* Retval LS 32bits */
+       unsigned long  r3;      /* Retval MS 32bits */
+       unsigned long  r4;      /* r4-r7 Register arguments */
+       unsigned long  r5;
+       unsigned long  r6;
+       unsigned long  r7;
+       unsigned long  orig_r2; /* Copy of r2 ?? */
+       unsigned long  ra;      /* Return address */
+       unsigned long  fp;      /* Frame pointer */
+       unsigned long  sp;      /* Stack pointer */
+       unsigned long  gp;      /* Global pointer */
+       unsigned long  estatus;
+       unsigned long  ea;      /* Exception return address (pc) */
+       unsigned long  orig_r7;
+};
+
+/*
+ * This is the extended stack used by signal handlers and the context
+ * switcher: it's pushed after the normal "struct pt_regs".
+ */
+struct switch_stack {
+       unsigned long  r16;     /* r16-r23 Callee-saved GP registers */
+       unsigned long  r17;
+       unsigned long  r18;
+       unsigned long  r19;
+       unsigned long  r20;
+       unsigned long  r21;
+       unsigned long  r22;
+       unsigned long  r23;
+       unsigned long  fp;
+       unsigned long  gp;
+       unsigned long  ra;
+};
+
 #define user_mode(regs)        (((regs)->estatus & ESTATUS_EU))
 
 #define instruction_pointer(regs)      ((regs)->ra)
diff --git a/arch/nios2/include/asm/ucontext.h b/arch/nios2/include/asm/ucontext.h
deleted file mode 100644 (file)
index 2c87614..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
- * Copyright (C) 2004 Microtronix Datacom Ltd
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_NIOS2_UCONTEXT_H
-#define _ASM_NIOS2_UCONTEXT_H
-
-typedef int greg_t;
-#define NGREG 32
-typedef greg_t gregset_t[NGREG];
-
-struct mcontext {
-       int version;
-       gregset_t gregs;
-};
-
-#define MCONTEXT_VERSION 2
-
-struct ucontext {
-       unsigned long     uc_flags;
-       struct ucontext  *uc_link;
-       stack_t           uc_stack;
-       struct mcontext   uc_mcontext;
-       sigset_t          uc_sigmask;   /* mask last for extensibility */
-};
-
-#endif
index 4f07ca3..e0bb972 100644 (file)
@@ -1,4 +1,5 @@
 include include/uapi/asm-generic/Kbuild.asm
 
 header-y += elf.h
-header-y += ucontext.h
+
+generic-y += ucontext.h
index a5b91ae..6f06d3b 100644 (file)
@@ -50,9 +50,7 @@
 
 typedef unsigned long elf_greg_t;
 
-#define ELF_NGREG      \
-       ((sizeof(struct pt_regs) + sizeof(struct switch_stack)) /       \
-               sizeof(elf_greg_t))
+#define ELF_NGREG              49
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 typedef unsigned long elf_fpregset_t;
index e83a7c9..71a3305 100644 (file)
 
 #define NUM_PTRACE_REG (PTR_TLBMISC + 1)
 
-/* this struct defines the way the registers are stored on the
-   stack during a system call.
-
-   There is a fake_regs in setup.c that has to match pt_regs.*/
-
-struct pt_regs {
-       unsigned long  r8;              /* r8-r15 Caller-saved GP registers */
-       unsigned long  r9;
-       unsigned long  r10;
-       unsigned long  r11;
-       unsigned long  r12;
-       unsigned long  r13;
-       unsigned long  r14;
-       unsigned long  r15;
-       unsigned long  r1;              /* Assembler temporary */
-       unsigned long  r2;              /* Retval LS 32bits */
-       unsigned long  r3;              /* Retval MS 32bits */
-       unsigned long  r4;              /* r4-r7 Register arguments */
-       unsigned long  r5;
-       unsigned long  r6;
-       unsigned long  r7;
-       unsigned long  orig_r2;         /* Copy of r2 ?? */
-       unsigned long  ra;              /* Return address */
-       unsigned long  fp;              /* Frame pointer */
-       unsigned long  sp;              /* Stack pointer */
-       unsigned long  gp;              /* Global pointer */
-       unsigned long  estatus;
-       unsigned long  ea;              /* Exception return address (pc) */
-       unsigned long  orig_r7;
-};
-
-/*
- * This is the extended stack used by signal handlers and the context
- * switcher: it's pushed after the normal "struct pt_regs".
- */
-struct switch_stack {
-       unsigned long  r16;             /* r16-r23 Callee-saved GP registers */
-       unsigned long  r17;
-       unsigned long  r18;
-       unsigned long  r19;
-       unsigned long  r20;
-       unsigned long  r21;
-       unsigned long  r22;
-       unsigned long  r23;
-       unsigned long  fp;
-       unsigned long  gp;
-       unsigned long  ra;
+/* User structures for general purpose registers.  */
+struct user_pt_regs {
+       __u32           regs[49];
 };
 
 #endif /* __ASSEMBLY__ */
index 7b8bb41..b67944a 100644 (file)
  * details.
  */
 
-#ifndef _ASM_NIOS2_SIGCONTEXT_H
-#define _ASM_NIOS2_SIGCONTEXT_H
+#ifndef _UAPI__ASM_SIGCONTEXT_H
+#define _UAPI__ASM_SIGCONTEXT_H
 
-#include <asm/ptrace.h>
+#include <linux/types.h>
+
+#define MCONTEXT_VERSION 2
 
 struct sigcontext {
-       struct pt_regs regs;
-       unsigned long  sc_mask; /* old sigmask */
+       int version;
+       unsigned long gregs[32];
 };
 
 #endif
index 2d0ea25..dda41e4 100644 (file)
@@ -39,7 +39,7 @@ static inline int rt_restore_ucontext(struct pt_regs *regs,
                                        struct ucontext *uc, int *pr2)
 {
        int temp;
-       greg_t *gregs = uc->uc_mcontext.gregs;
+       unsigned long *gregs = uc->uc_mcontext.gregs;
        int err;
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -127,7 +127,7 @@ badframe:
 static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
 {
        struct switch_stack *sw = (struct switch_stack *)regs - 1;
-       greg_t *gregs = uc->uc_mcontext.gregs;
+       unsigned long *gregs = uc->uc_mcontext.gregs;
        int err = 0;
 
        err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
index 0d231ad..0c9b6af 100644 (file)
@@ -126,7 +126,6 @@ good_area:
                break;
        }
 
-survive:
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -220,11 +219,6 @@ no_context:
  */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_global_init(tsk)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
        if (!user_mode(regs))
                goto no_context;
        pagefault_out_of_memory();
index f213f5b..d174372 100644 (file)
@@ -26,7 +26,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
        if (likely(pgd != NULL)) {
                memset(pgd, 0, PAGE_SIZE<<PGD_ALLOC_ORDER);
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
                actual_pgd += PTRS_PER_PGD;
                /* Populate first pmd with allocated memory.  We mark it
                 * with PxD_FLAG_ATTACHED as a signal to the system that this
@@ -45,7 +45,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
        pgd -= PTRS_PER_PGD;
 #endif
        free_pages((unsigned long)pgd, PGD_ALLOC_ORDER);
@@ -72,12 +72,15 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
-#ifdef CONFIG_64BIT
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
-               /* This is the permanent pmd attached to the pgd;
-                * cannot free it */
+               /*
+                * This is the permanent pmd attached to the pgd;
+                * cannot free it.
+                * Increment the counter to compensate for the decrement
+                * done by generic mm code.
+                */
+               mm_inc_nr_pmds(mm);
                return;
-#endif
        free_pages((unsigned long)pmd, PMD_ORDER);
 }
 
@@ -99,7 +102,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 static inline void
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
        /* preserve the gateway marker if this is the beginning of
         * the permanent pmd */
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
index 8c966b2..15207b9 100644 (file)
@@ -96,6 +96,7 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long);
 #if PT_NLEVELS == 3
 #define BITS_PER_PMD   (PAGE_SHIFT + PMD_ORDER - BITS_PER_PMD_ENTRY)
 #else
+#define __PAGETABLE_PMD_FOLDED
 #define BITS_PER_PMD   0
 #endif
 #define PTRS_PER_PMD    (1UL << BITS_PER_PMD)
index 5a8997d..8eefb12 100644 (file)
@@ -55,8 +55,8 @@
 #define ENTRY_COMP(_name_) .word sys_##_name_
 #endif
 
-       ENTRY_SAME(restart_syscall)     /* 0 */
-       ENTRY_SAME(exit)
+90:    ENTRY_SAME(restart_syscall)     /* 0 */
+91:    ENTRY_SAME(exit)
        ENTRY_SAME(fork_wrapper)
        ENTRY_SAME(read)
        ENTRY_SAME(write)
        ENTRY_SAME(bpf)
        ENTRY_COMP(execveat)
 
-       /* Nothing yet */
+
+.ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b))
+.error "size of syscall table does not fit value of __NR_Linux_syscalls"
+.endif
 
 #undef ENTRY_SAME
 #undef ENTRY_DIFF
index 2bf8e93..4c8ad59 100644 (file)
@@ -55,7 +55,7 @@ static inline cpumask_t cpu_thread_mask_to_cores(const struct cpumask *threads)
 
 static inline int cpu_nr_cores(void)
 {
-       return NR_CPUS >> threads_shift;
+       return nr_cpu_ids >> threads_shift;
 }
 
 static inline cpumask_t cpu_online_cores_map(void)
index 9cfa370..f1ea597 100644 (file)
@@ -113,6 +113,7 @@ extern void iommu_register_group(struct iommu_table *tbl,
                                 int pci_domain_number, unsigned long pe_num);
 extern int iommu_add_device(struct device *dev);
 extern void iommu_del_device(struct device *dev);
+extern int __init tce_iommu_bus_notifier_init(void);
 #else
 static inline void iommu_register_group(struct iommu_table *tbl,
                                        int pci_domain_number,
@@ -128,6 +129,11 @@ static inline int iommu_add_device(struct device *dev)
 static inline void iommu_del_device(struct device *dev)
 {
 }
+
+static inline int __init tce_iommu_bus_notifier_init(void)
+{
+        return 0;
+}
 #endif /* !CONFIG_IOMMU_API */
 
 static inline void set_iommu_table_base_and_group(struct device *dev,
diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h
new file mode 100644 (file)
index 0000000..744fd54
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _ASM_POWERPC_IRQ_WORK_H
+#define _ASM_POWERPC_IRQ_WORK_H
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+       return true;
+}
+
+#endif /* _ASM_POWERPC_IRQ_WORK_H */
index 03cd858..4cbe23a 100644 (file)
 #define PPC_INST_MFSPR_PVR_MASK                0xfc1fffff
 #define PPC_INST_MFTMR                 0x7c0002dc
 #define PPC_INST_MSGSND                        0x7c00019c
+#define PPC_INST_MSGCLR                        0x7c0001dc
 #define PPC_INST_MSGSNDP               0x7c00011c
 #define PPC_INST_MTTMR                 0x7c0003dc
 #define PPC_INST_NOP                   0x60000000
                                        ___PPC_RB(b) | __PPC_EH(eh))
 #define PPC_MSGSND(b)          stringify_in_c(.long PPC_INST_MSGSND | \
                                        ___PPC_RB(b))
+#define PPC_MSGCLR(b)          stringify_in_c(.long PPC_INST_MSGCLR | \
+                                       ___PPC_RB(b))
 #define PPC_MSGSNDP(b)         stringify_in_c(.long PPC_INST_MSGSNDP | \
                                        ___PPC_RB(b))
 #define PPC_POPCNTB(a, s)      stringify_in_c(.long PPC_INST_POPCNTB | \
index 1c874fb..af56b5c 100644 (file)
 #define   SRR1_ISI_N_OR_G      0x10000000 /* ISI: Access is no-exec or G */
 #define   SRR1_ISI_PROT                0x08000000 /* ISI: Other protection fault */
 #define   SRR1_WAKEMASK                0x00380000 /* reason for wakeup */
+#define   SRR1_WAKEMASK_P8     0x003c0000 /* reason for wakeup on POWER8 */
 #define   SRR1_WAKESYSERR      0x00300000 /* System error */
 #define   SRR1_WAKEEE          0x00200000 /* External interrupt */
 #define   SRR1_WAKEMT          0x00280000 /* mtctrl */
 #define          SRR1_WAKEHMI          0x00280000 /* Hypervisor maintenance */
 #define   SRR1_WAKEDEC         0x00180000 /* Decrementer interrupt */
+#define   SRR1_WAKEDBELL       0x00140000 /* Privileged doorbell on P8 */
 #define   SRR1_WAKETHERM       0x00100000 /* Thermal management interrupt */
 #define          SRR1_WAKERESET        0x00100000 /* System reset */
+#define   SRR1_WAKEHDBELL      0x000c0000 /* Hypervisor doorbell on P8 */
 #define          SRR1_WAKESTATE        0x00030000 /* Powersave exit mask [46:47] */
 #define          SRR1_WS_DEEPEST       0x00030000 /* Some resources not maintained,
                                          * may not be recoverable */
index f337666..f830468 100644 (file)
@@ -437,6 +437,26 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
+       {       /* Power8NVL */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x004c0000,
+               .cpu_name               = "POWER8NVL (raw)",
+               .cpu_features           = CPU_FTRS_POWER8,
+               .cpu_user_features      = COMMON_USER_POWER8,
+               .cpu_user_features2     = COMMON_USER2_POWER8,
+               .mmu_features           = MMU_FTRS_POWER8,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_IBM,
+               .oprofile_cpu_type      = "ppc64/power8",
+               .oprofile_type          = PPC_OPROFILE_INVALID,
+               .cpu_setup              = __setup_cpu_power8,
+               .cpu_restore            = __restore_cpu_power8,
+               .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
+               .platform               = "power8",
+       },
        {       /* Power8 DD1: Does not support doorbell IPIs */
                .pvr_mask               = 0xffffff00,
                .pvr_value              = 0x004d0100,
index f421781..2128f3a 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/dbell.h>
 #include <asm/irq_regs.h>
+#include <asm/kvm_ppc.h>
 
 #ifdef CONFIG_SMP
 void doorbell_setup_this_cpu(void)
@@ -41,6 +42,7 @@ void doorbell_exception(struct pt_regs *regs)
 
        may_hard_irq_enable();
 
+       kvmppc_set_host_ipi(smp_processor_id(), 0);
        __this_cpu_inc(irq_stat.doorbell_irqs);
 
        smp_ipi_demux();
index c2df815..9519e6b 100644 (file)
@@ -1408,7 +1408,7 @@ machine_check_handle_early:
        bne     9f                      /* continue in V mode if we are. */
 
 5:
-#ifdef CONFIG_KVM_BOOK3S_64_HV
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
        /*
         * We are coming from kernel context. Check if we are coming from
         * guest. if yes, then we can continue. We will fall through
index 5d3968c..b054f33 100644 (file)
@@ -1175,4 +1175,30 @@ void iommu_del_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(iommu_del_device);
 
+static int tce_iommu_bus_notifier(struct notifier_block *nb,
+                unsigned long action, void *data)
+{
+        struct device *dev = data;
+
+        switch (action) {
+        case BUS_NOTIFY_ADD_DEVICE:
+                return iommu_add_device(dev);
+        case BUS_NOTIFY_DEL_DEVICE:
+                if (dev->iommu_group)
+                        iommu_del_device(dev);
+                return 0;
+        default:
+                return 0;
+        }
+}
+
+static struct notifier_block tce_iommu_bus_nb = {
+        .notifier_call = tce_iommu_bus_notifier,
+};
+
+int __init tce_iommu_bus_notifier_init(void)
+{
+        bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+        return 0;
+}
 #endif /* CONFIG_IOMMU_API */
index 6e19afa..ec9ec20 100644 (file)
@@ -541,8 +541,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
        if (smp_ops->give_timebase)
                smp_ops->give_timebase();
 
-       /* Wait until cpu puts itself in the online map */
-       while (!cpu_online(cpu))
+       /* Wait until cpu puts itself in the online & active maps */
+       while (!cpu_online(cpu) || !cpu_active(cpu))
                cpu_relax();
 
        return 0;
index de4018a..de74756 100644 (file)
@@ -636,7 +636,7 @@ static int kvmppc_get_yield_count(struct kvm_vcpu *vcpu)
        spin_lock(&vcpu->arch.vpa_update_lock);
        lppaca = (struct lppaca *)vcpu->arch.vpa.pinned_addr;
        if (lppaca)
-               yield_count = lppaca->yield_count;
+               yield_count = be32_to_cpu(lppaca->yield_count);
        spin_unlock(&vcpu->arch.vpa_update_lock);
        return yield_count;
 }
@@ -942,20 +942,20 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,
 static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                bool preserve_top32)
 {
+       struct kvm *kvm = vcpu->kvm;
        struct kvmppc_vcore *vc = vcpu->arch.vcore;
        u64 mask;
 
+       mutex_lock(&kvm->lock);
        spin_lock(&vc->lock);
        /*
         * If ILE (interrupt little-endian) has changed, update the
         * MSR_LE bit in the intr_msr for each vcpu in this vcore.
         */
        if ((new_lpcr & LPCR_ILE) != (vc->lpcr & LPCR_ILE)) {
-               struct kvm *kvm = vcpu->kvm;
                struct kvm_vcpu *vcpu;
                int i;
 
-               mutex_lock(&kvm->lock);
                kvm_for_each_vcpu(i, vcpu, kvm) {
                        if (vcpu->arch.vcore != vc)
                                continue;
@@ -964,7 +964,6 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                        else
                                vcpu->arch.intr_msr &= ~MSR_LE;
                }
-               mutex_unlock(&kvm->lock);
        }
 
        /*
@@ -981,6 +980,7 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                mask &= 0xFFFFFFFF;
        vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);
        spin_unlock(&vc->lock);
+       mutex_unlock(&kvm->lock);
 }
 
 static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
index bb94e6f..6cbf163 100644 (file)
@@ -1005,6 +1005,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        /* Save HEIR (HV emulation assist reg) in emul_inst
           if this is an HEI (HV emulation interrupt, e40) */
        li      r3,KVM_INST_FETCH_FAILED
+       stw     r3,VCPU_LAST_INST(r9)
        cmpwi   r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
        bne     11f
        mfspr   r3,SPRN_HEIR
index e69142f..54323d6 100644 (file)
@@ -836,30 +836,4 @@ void __init pnv_pci_init(void)
 #endif
 }
 
-static int tce_iommu_bus_notifier(struct notifier_block *nb,
-               unsigned long action, void *data)
-{
-       struct device *dev = data;
-
-       switch (action) {
-       case BUS_NOTIFY_ADD_DEVICE:
-               return iommu_add_device(dev);
-       case BUS_NOTIFY_DEL_DEVICE:
-               if (dev->iommu_group)
-                       iommu_del_device(dev);
-               return 0;
-       default:
-               return 0;
-       }
-}
-
-static struct notifier_block tce_iommu_bus_nb = {
-       .notifier_call = tce_iommu_bus_notifier,
-};
-
-static int __init tce_iommu_bus_notifier_init(void)
-{
-       bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
-       return 0;
-}
 machine_subsys_initcall_sync(powernv, tce_iommu_bus_notifier_init);
index fc34025..38a4508 100644 (file)
@@ -33,6 +33,8 @@
 #include <asm/runlatch.h>
 #include <asm/code-patching.h>
 #include <asm/dbell.h>
+#include <asm/kvm_ppc.h>
+#include <asm/ppc-opcode.h>
 
 #include "powernv.h"
 
@@ -149,7 +151,7 @@ static int pnv_smp_cpu_disable(void)
 static void pnv_smp_cpu_kill_self(void)
 {
        unsigned int cpu;
-       unsigned long srr1;
+       unsigned long srr1, wmask;
        u32 idle_states;
 
        /* Standard hot unplug procedure */
@@ -161,6 +163,10 @@ static void pnv_smp_cpu_kill_self(void)
        generic_set_cpu_dead(cpu);
        smp_wmb();
 
+       wmask = SRR1_WAKEMASK;
+       if (cpu_has_feature(CPU_FTR_ARCH_207S))
+               wmask = SRR1_WAKEMASK_P8;
+
        idle_states = pnv_get_supported_cpuidle_states();
        /* We don't want to take decrementer interrupts while we are offline,
         * so clear LPCR:PECE1. We keep PECE2 enabled.
@@ -191,10 +197,14 @@ static void pnv_smp_cpu_kill_self(void)
                 * having finished executing in a KVM guest, then srr1
                 * contains 0.
                 */
-               if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) {
+               if ((srr1 & wmask) == SRR1_WAKEEE) {
                        icp_native_flush_interrupt();
                        local_paca->irq_happened &= PACA_IRQ_HARD_DIS;
                        smp_mb();
+               } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
+                       unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
+                       asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
+                       kvmppc_set_host_ipi(cpu, 0);
                }
 
                if (cpu_core_split_required())
index 1d3d52d..7803a19 100644 (file)
@@ -1340,3 +1340,5 @@ static int __init disable_multitce(char *str)
 }
 
 __setup("multitce=", disable_multitce);
+
+machine_subsys_initcall_sync(pseries, tce_iommu_bus_notifier_init);
index 90cf3dc..8f35d52 100644 (file)
 static struct kobject *mobility_kobj;
 
 struct update_props_workarea {
-       u32 phandle;
-       u32 state;
-       u64 reserved;
-       u32 nprops;
+       __be32 phandle;
+       __be32 state;
+       __be64 reserved;
+       __be32 nprops;
 } __packed;
 
 #define NODE_ACTION_MASK       0xff000000
@@ -54,11 +54,11 @@ static int mobility_rtas_call(int token, char *buf, s32 scope)
        return rc;
 }
 
-static int delete_dt_node(u32 phandle)
+static int delete_dt_node(__be32 phandle)
 {
        struct device_node *dn;
 
-       dn = of_find_node_by_phandle(phandle);
+       dn = of_find_node_by_phandle(be32_to_cpu(phandle));
        if (!dn)
                return -ENOENT;
 
@@ -127,7 +127,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
        return 0;
 }
 
-static int update_dt_node(u32 phandle, s32 scope)
+static int update_dt_node(__be32 phandle, s32 scope)
 {
        struct update_props_workarea *upwa;
        struct device_node *dn;
@@ -136,6 +136,7 @@ static int update_dt_node(u32 phandle, s32 scope)
        char *prop_data;
        char *rtas_buf;
        int update_properties_token;
+       u32 nprops;
        u32 vd;
 
        update_properties_token = rtas_token("ibm,update-properties");
@@ -146,7 +147,7 @@ static int update_dt_node(u32 phandle, s32 scope)
        if (!rtas_buf)
                return -ENOMEM;
 
-       dn = of_find_node_by_phandle(phandle);
+       dn = of_find_node_by_phandle(be32_to_cpu(phandle));
        if (!dn) {
                kfree(rtas_buf);
                return -ENOENT;
@@ -162,6 +163,7 @@ static int update_dt_node(u32 phandle, s32 scope)
                        break;
 
                prop_data = rtas_buf + sizeof(*upwa);
+               nprops = be32_to_cpu(upwa->nprops);
 
                /* On the first call to ibm,update-properties for a node the
                 * the first property value descriptor contains an empty
@@ -170,17 +172,17 @@ static int update_dt_node(u32 phandle, s32 scope)
                 */
                if (*prop_data == 0) {
                        prop_data++;
-                       vd = *(u32 *)prop_data;
+                       vd = be32_to_cpu(*(__be32 *)prop_data);
                        prop_data += vd + sizeof(vd);
-                       upwa->nprops--;
+                       nprops--;
                }
 
-               for (i = 0; i < upwa->nprops; i++) {
+               for (i = 0; i < nprops; i++) {
                        char *prop_name;
 
                        prop_name = prop_data;
                        prop_data += strlen(prop_name) + 1;
-                       vd = *(u32 *)prop_data;
+                       vd = be32_to_cpu(*(__be32 *)prop_data);
                        prop_data += sizeof(vd);
 
                        switch (vd) {
@@ -212,13 +214,13 @@ static int update_dt_node(u32 phandle, s32 scope)
        return 0;
 }
 
-static int add_dt_node(u32 parent_phandle, u32 drc_index)
+static int add_dt_node(__be32 parent_phandle, __be32 drc_index)
 {
        struct device_node *dn;
        struct device_node *parent_dn;
        int rc;
 
-       parent_dn = of_find_node_by_phandle(parent_phandle);
+       parent_dn = of_find_node_by_phandle(be32_to_cpu(parent_phandle));
        if (!parent_dn)
                return -ENOENT;
 
@@ -237,7 +239,7 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index)
 int pseries_devicetree_update(s32 scope)
 {
        char *rtas_buf;
-       u32 *data;
+       __be32 *data;
        int update_nodes_token;
        int rc;
 
@@ -254,17 +256,17 @@ int pseries_devicetree_update(s32 scope)
                if (rc && rc != 1)
                        break;
 
-               data = (u32 *)rtas_buf + 4;
-               while (*data & NODE_ACTION_MASK) {
+               data = (__be32 *)rtas_buf + 4;
+               while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
                        int i;
-                       u32 action = *data & NODE_ACTION_MASK;
-                       int node_count = *data & NODE_COUNT_MASK;
+                       u32 action = be32_to_cpu(*data) & NODE_ACTION_MASK;
+                       u32 node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
 
                        data++;
 
                        for (i = 0; i < node_count; i++) {
-                               u32 phandle = *data++;
-                               u32 drc_index;
+                               __be32 phandle = *data++;
+                               __be32 drc_index;
 
                                switch (action) {
                                case DELETE_DT_NODE:
index c9df40b..c9c875d 100644 (file)
@@ -211,7 +211,7 @@ do {                                                                \
 
 extern unsigned long mmap_rnd_mask;
 
-#define STACK_RND_MASK (mmap_rnd_mask)
+#define STACK_RND_MASK (test_thread_flag(TIF_31BIT) ? 0x7ff : mmap_rnd_mask)
 
 #define ARCH_DLINFO                                                        \
 do {                                                                       \
index d84559e..f407bbf 100644 (file)
@@ -515,15 +515,15 @@ struct s390_io_adapter {
 #define S390_ARCH_FAC_MASK_SIZE_U64 \
        (S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))
 
-struct s390_model_fac {
-       /* facilities used in SIE context */
-       __u64 sie[S390_ARCH_FAC_LIST_SIZE_U64];
-       /* subset enabled by kvm */
-       __u64 kvm[S390_ARCH_FAC_LIST_SIZE_U64];
+struct kvm_s390_fac {
+       /* facility list requested by guest */
+       __u64 list[S390_ARCH_FAC_LIST_SIZE_U64];
+       /* facility mask supported by kvm & hosting machine */
+       __u64 mask[S390_ARCH_FAC_LIST_SIZE_U64];
 };
 
 struct kvm_s390_cpu_model {
-       struct s390_model_fac *fac;
+       struct kvm_s390_fac *fac;
        struct cpuid cpu_id;
        unsigned short ibc;
 };
index f49b719..8fb3802 100644 (file)
@@ -62,6 +62,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        int cpu = smp_processor_id();
 
+       S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd);
        if (prev == next)
                return;
        if (MACHINE_HAS_TLB_LC)
@@ -73,7 +74,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        atomic_dec(&prev->context.attach_count);
        if (MACHINE_HAS_TLB_LC)
                cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
-       S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd);
 }
 
 #define finish_arch_post_lock_switch finish_arch_post_lock_switch
index 7b2ac6e..53eacbd 100644 (file)
@@ -37,16 +37,7 @@ static inline void storage_key_init_range(unsigned long start, unsigned long end
 #endif
 }
 
-static inline void clear_page(void *page)
-{
-       register unsigned long reg1 asm ("1") = 0;
-       register void *reg2 asm ("2") = page;
-       register unsigned long reg3 asm ("3") = 4096;
-       asm volatile(
-               "       mvcl    2,0"
-               : "+d" (reg2), "+d" (reg3) : "d" (reg1)
-               : "memory", "cc");
-}
+#define clear_page(page)       memset((page), 0, PAGE_SIZE)
 
 /*
  * copy_page uses the mvcl instruction with 0xb0 padding byte in order to
index fbb5ee3..e08ec38 100644 (file)
@@ -91,7 +91,9 @@ extern unsigned long zero_page_mask;
  */
 #define PTRS_PER_PTE   256
 #ifndef CONFIG_64BIT
+#define __PAGETABLE_PUD_FOLDED
 #define PTRS_PER_PMD   1
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PUD   1
 #else /* CONFIG_64BIT */
 #define PTRS_PER_PMD   2048
index 82c1989..6c79f1b 100644 (file)
 
 unsigned long ftrace_plt;
 
+static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn)
+{
+#ifdef CC_USING_HOTPATCH
+       /* brcl 0,0 */
+       insn->opc = 0xc004;
+       insn->disp = 0;
+#else
+       /* stg r14,8(r15) */
+       insn->opc = 0xe3e0;
+       insn->disp = 0xf0080024;
+#endif
+}
+
+static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       if (insn->opc == BREAKPOINT_INSTRUCTION)
+               return 1;
+#endif
+       return 0;
+}
+
+static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       insn->opc = BREAKPOINT_INSTRUCTION;
+       insn->disp = KPROBE_ON_FTRACE_NOP;
+#endif
+}
+
+static inline void ftrace_generate_kprobe_call_insn(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       insn->opc = BREAKPOINT_INSTRUCTION;
+       insn->disp = KPROBE_ON_FTRACE_CALL;
+#endif
+}
+
 int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
                       unsigned long addr)
 {
@@ -72,16 +110,9 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                return -EFAULT;
        if (addr == MCOUNT_ADDR) {
                /* Initial code replacement */
-#ifdef CC_USING_HOTPATCH
-               /* We expect to see brcl 0,0 */
-               ftrace_generate_nop_insn(&orig);
-#else
-               /* We expect to see stg r14,8(r15) */
-               orig.opc = 0xe3e0;
-               orig.disp = 0xf0080024;
-#endif
+               ftrace_generate_orig_insn(&orig);
                ftrace_generate_nop_insn(&new);
-       } else if (old.opc == BREAKPOINT_INSTRUCTION) {
+       } else if (is_kprobe_on_ftrace(&old)) {
                /*
                 * If we find a breakpoint instruction, a kprobe has been
                 * placed at the beginning of the function. We write the
@@ -89,9 +120,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                 * bytes of the original instruction so that the kprobes
                 * handler can execute a nop, if it reaches this breakpoint.
                 */
-               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
-               orig.disp = KPROBE_ON_FTRACE_CALL;
-               new.disp = KPROBE_ON_FTRACE_NOP;
+               ftrace_generate_kprobe_call_insn(&orig);
+               ftrace_generate_kprobe_nop_insn(&new);
        } else {
                /* Replace ftrace call with a nop. */
                ftrace_generate_call_insn(&orig, rec->ip);
@@ -111,7 +141,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 
        if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
                return -EFAULT;
-       if (old.opc == BREAKPOINT_INSTRUCTION) {
+       if (is_kprobe_on_ftrace(&old)) {
                /*
                 * If we find a breakpoint instruction, a kprobe has been
                 * placed at the beginning of the function. We write the
@@ -119,9 +149,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
                 * bytes of the original instruction so that the kprobes
                 * handler can execute a brasl if it reaches this breakpoint.
                 */
-               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
-               orig.disp = KPROBE_ON_FTRACE_NOP;
-               new.disp = KPROBE_ON_FTRACE_CALL;
+               ftrace_generate_kprobe_nop_insn(&orig);
+               ftrace_generate_kprobe_call_insn(&new);
        } else {
                /* Replace nop with an ftrace call. */
                ftrace_generate_nop_insn(&orig);
index cb2d51e..830066f 100644 (file)
@@ -36,16 +36,20 @@ static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
        insn->offset = (entry->target - entry->code) >> 1;
 }
 
-static void jump_label_bug(struct jump_entry *entry, struct insn *insn)
+static void jump_label_bug(struct jump_entry *entry, struct insn *expected,
+                          struct insn *new)
 {
        unsigned char *ipc = (unsigned char *)entry->code;
-       unsigned char *ipe = (unsigned char *)insn;
+       unsigned char *ipe = (unsigned char *)expected;
+       unsigned char *ipn = (unsigned char *)new;
 
        pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc, ipc);
        pr_emerg("Found:    %02x %02x %02x %02x %02x %02x\n",
                 ipc[0], ipc[1], ipc[2], ipc[3], ipc[4], ipc[5]);
        pr_emerg("Expected: %02x %02x %02x %02x %02x %02x\n",
                 ipe[0], ipe[1], ipe[2], ipe[3], ipe[4], ipe[5]);
+       pr_emerg("New:      %02x %02x %02x %02x %02x %02x\n",
+                ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], ipn[5]);
        panic("Corrupted kernel text");
 }
 
@@ -69,10 +73,10 @@ static void __jump_label_transform(struct jump_entry *entry,
        }
        if (init) {
                if (memcmp((void *)entry->code, &orignop, sizeof(orignop)))
-                       jump_label_bug(entry, &old);
+                       jump_label_bug(entry, &orignop, &new);
        } else {
                if (memcmp((void *)entry->code, &old, sizeof(old)))
-                       jump_label_bug(entry, &old);
+                       jump_label_bug(entry, &old, &new);
        }
        probe_kernel_write((void *)entry->code, &new, sizeof(new));
 }
index 36154a2..2ca9586 100644 (file)
@@ -436,6 +436,7 @@ int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
+       jump_label_apply_nops(me);
        vfree(me->arch.syminfo);
        me->arch.syminfo = NULL;
        return 0;
index c3f8d15..e6a1578 100644 (file)
@@ -1415,7 +1415,7 @@ CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC_DIAG, PERF_EVENT_CPUM_SF_DIAG);
 
 static struct attribute *cpumsf_pmu_events_attr[] = {
        CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC),
-       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG),
+       NULL,
        NULL,
 };
 
@@ -1606,8 +1606,11 @@ static int __init init_cpum_sampling_pmu(void)
                return -EINVAL;
        }
 
-       if (si.ad)
+       if (si.ad) {
                sfb_set_limits(CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB);
+               cpumsf_pmu_events_attr[1] =
+                       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG);
+       }
 
        sfdbg = debug_register(KMSG_COMPONENT, 2, 1, 80);
        if (!sfdbg)
index 2610823..dc488e1 100644 (file)
@@ -18,7 +18,7 @@
 
 static DEFINE_PER_CPU(struct cpuid, cpu_id);
 
-void cpu_relax(void)
+void notrace cpu_relax(void)
 {
        if (!smp_cpu_mtid && MACHINE_HAS_DIAG44)
                asm volatile("diag 0,0,0x44");
index 6b09fdf..ca62946 100644 (file)
@@ -177,6 +177,17 @@ restart_entry:
        lhi     %r1,1
        sigp    %r1,%r0,SIGP_SET_ARCHITECTURE
        sam64
+#ifdef CONFIG_SMP
+       larl    %r1,smp_cpu_mt_shift
+       icm     %r1,15,0(%r1)
+       jz      smt_done
+       llgfr   %r1,%r1
+smt_loop:
+       sigp    %r1,%r0,SIGP_SET_MULTI_THREADING
+       brc     8,smt_done                      /* accepted */
+       brc     2,smt_loop                      /* busy, try again */
+smt_done:
+#endif
        larl    %r1,.Lnew_pgm_check_psw
        lpswe   0(%r1)
 pgm_check_entry:
index 0c36239..19e17bd 100644 (file)
@@ -165,7 +165,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_ONE_REG:
        case KVM_CAP_ENABLE_CAP:
        case KVM_CAP_S390_CSS_SUPPORT:
-       case KVM_CAP_IRQFD:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_DEVICE_CTRL:
        case KVM_CAP_ENABLE_CAP_VM:
@@ -522,7 +521,7 @@ static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr)
                memcpy(&kvm->arch.model.cpu_id, &proc->cpuid,
                       sizeof(struct cpuid));
                kvm->arch.model.ibc = proc->ibc;
-               memcpy(kvm->arch.model.fac->kvm, proc->fac_list,
+               memcpy(kvm->arch.model.fac->list, proc->fac_list,
                       S390_ARCH_FAC_LIST_SIZE_BYTE);
        } else
                ret = -EFAULT;
@@ -556,7 +555,7 @@ static int kvm_s390_get_processor(struct kvm *kvm, struct kvm_device_attr *attr)
        }
        memcpy(&proc->cpuid, &kvm->arch.model.cpu_id, sizeof(struct cpuid));
        proc->ibc = kvm->arch.model.ibc;
-       memcpy(&proc->fac_list, kvm->arch.model.fac->kvm, S390_ARCH_FAC_LIST_SIZE_BYTE);
+       memcpy(&proc->fac_list, kvm->arch.model.fac->list, S390_ARCH_FAC_LIST_SIZE_BYTE);
        if (copy_to_user((void __user *)attr->addr, proc, sizeof(*proc)))
                ret = -EFAULT;
        kfree(proc);
@@ -576,10 +575,10 @@ static int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr)
        }
        get_cpu_id((struct cpuid *) &mach->cpuid);
        mach->ibc = sclp_get_ibc();
-       memcpy(&mach->fac_mask, kvm_s390_fac_list_mask,
-              kvm_s390_fac_list_mask_size() * sizeof(u64));
+       memcpy(&mach->fac_mask, kvm->arch.model.fac->mask,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        memcpy((unsigned long *)&mach->fac_list, S390_lowcore.stfle_fac_list,
-              S390_ARCH_FAC_LIST_SIZE_U64);
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        if (copy_to_user((void __user *)attr->addr, mach, sizeof(*mach)))
                ret = -EFAULT;
        kfree(mach);
@@ -778,15 +777,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
 static int kvm_s390_query_ap_config(u8 *config)
 {
        u32 fcn_code = 0x04000000UL;
-       u32 cc;
+       u32 cc = 0;
 
+       memset(config, 0, 128);
        asm volatile(
                "lgr 0,%1\n"
                "lgr 2,%2\n"
                ".long 0xb2af0000\n"            /* PQAP(QCI) */
-               "ipm %0\n"
+               "0: ipm %0\n"
                "srl %0,28\n"
-               : "=r" (cc)
+               "1:\n"
+               EX_TABLE(0b, 1b)
+               : "+r" (cc)
                : "r" (fcn_code), "r" (config)
                : "cc", "0", "2", "memory"
        );
@@ -839,9 +841,13 @@ static int kvm_s390_crypto_init(struct kvm *kvm)
 
        kvm_s390_set_crycb_format(kvm);
 
-       /* Disable AES/DEA protected key functions by default */
-       kvm->arch.crypto.aes_kw = 0;
-       kvm->arch.crypto.dea_kw = 0;
+       /* Enable AES/DEA protected key functions by default */
+       kvm->arch.crypto.aes_kw = 1;
+       kvm->arch.crypto.dea_kw = 1;
+       get_random_bytes(kvm->arch.crypto.crycb->aes_wrapping_key_mask,
+                        sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask));
+       get_random_bytes(kvm->arch.crypto.crycb->dea_wrapping_key_mask,
+                        sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask));
 
        return 0;
 }
@@ -886,40 +892,29 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        /*
         * The architectural maximum amount of facilities is 16 kbit. To store
         * this amount, 2 kbyte of memory is required. Thus we need a full
-        * page to hold the active copy (arch.model.fac->sie) and the current
-        * facilities set (arch.model.fac->kvm). Its address size has to be
+        * page to hold the guest facility list (arch.model.fac->list) and the
+        * facility mask (arch.model.fac->mask). Its address size has to be
         * 31 bits and word aligned.
         */
        kvm->arch.model.fac =
-               (struct s390_model_fac *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+               (struct kvm_s390_fac *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!kvm->arch.model.fac)
                goto out_nofac;
 
-       memcpy(kvm->arch.model.fac->kvm, S390_lowcore.stfle_fac_list,
-              S390_ARCH_FAC_LIST_SIZE_U64);
-
-       /*
-        * If this KVM host runs *not* in a LPAR, relax the facility bits
-        * of the kvm facility mask by all missing facilities. This will allow
-        * to determine the right CPU model by means of the remaining facilities.
-        * Live guest migration must prohibit the migration of KVMs running in
-        * a LPAR to non LPAR hosts.
-        */
-       if (!MACHINE_IS_LPAR)
-               for (i = 0; i < kvm_s390_fac_list_mask_size(); i++)
-                       kvm_s390_fac_list_mask[i] &= kvm->arch.model.fac->kvm[i];
-
-       /*
-        * Apply the kvm facility mask to limit the kvm supported/tolerated
-        * facility list.
-        */
+       /* Populate the facility mask initially. */
+       memcpy(kvm->arch.model.fac->mask, S390_lowcore.stfle_fac_list,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        for (i = 0; i < S390_ARCH_FAC_LIST_SIZE_U64; i++) {
                if (i < kvm_s390_fac_list_mask_size())
-                       kvm->arch.model.fac->kvm[i] &= kvm_s390_fac_list_mask[i];
+                       kvm->arch.model.fac->mask[i] &= kvm_s390_fac_list_mask[i];
                else
-                       kvm->arch.model.fac->kvm[i] = 0UL;
+                       kvm->arch.model.fac->mask[i] = 0UL;
        }
 
+       /* Populate the facility list initially. */
+       memcpy(kvm->arch.model.fac->list, kvm->arch.model.fac->mask,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
+
        kvm_s390_get_cpu_id(&kvm->arch.model.cpu_id);
        kvm->arch.model.ibc = sclp_get_ibc() & 0x0fff;
 
@@ -1165,8 +1160,6 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 
        mutex_lock(&vcpu->kvm->lock);
        vcpu->arch.cpu_id = vcpu->kvm->arch.model.cpu_id;
-       memcpy(vcpu->kvm->arch.model.fac->sie, vcpu->kvm->arch.model.fac->kvm,
-              S390_ARCH_FAC_LIST_SIZE_BYTE);
        vcpu->arch.sie_block->ibc = vcpu->kvm->arch.model.ibc;
        mutex_unlock(&vcpu->kvm->lock);
 
@@ -1212,7 +1205,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
                set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
        }
-       vcpu->arch.sie_block->fac = (int) (long) kvm->arch.model.fac->sie;
+       vcpu->arch.sie_block->fac = (int) (long) kvm->arch.model.fac->list;
 
        spin_lock_init(&vcpu->arch.local_int.lock);
        vcpu->arch.local_int.float_int = &kvm->arch.float_int;
index 985c211..c34109a 100644 (file)
@@ -128,7 +128,8 @@ static inline void kvm_s390_set_psw_cc(struct kvm_vcpu *vcpu, unsigned long cc)
 /* test availability of facility in a kvm intance */
 static inline int test_kvm_facility(struct kvm *kvm, unsigned long nr)
 {
-       return __test_facility(nr, kvm->arch.model.fac->kvm);
+       return __test_facility(nr, kvm->arch.model.fac->mask) &&
+               __test_facility(nr, kvm->arch.model.fac->list);
 }
 
 /* are cpu states controlled by user space */
index bdd9b5b..3511169 100644 (file)
@@ -348,7 +348,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
         * We need to shift the lower 32 facility bits (bit 0-31) from a u64
         * into a u32 memory representation. They will remain bits 0-31.
         */
-       fac = *vcpu->kvm->arch.model.fac->sie >> 32;
+       fac = *vcpu->kvm->arch.model.fac->list >> 32;
        rc = write_guest_lc(vcpu, offsetof(struct _lowcore, stfl_fac_list),
                            &fac, sizeof(fac));
        if (rc)
index 753a567..f0b8544 100644 (file)
@@ -287,7 +287,7 @@ void __iomem *pci_iomap_range(struct pci_dev *pdev,
        addr = ZPCI_IOMAP_ADDR_BASE | ((u64) idx << 48);
        return (void __iomem *) addr + offset;
 }
-EXPORT_SYMBOL_GPL(pci_iomap_range);
+EXPORT_SYMBOL(pci_iomap_range);
 
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
 {
@@ -309,7 +309,7 @@ void pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
        }
        spin_unlock(&zpci_iomap_lock);
 }
-EXPORT_SYMBOL_GPL(pci_iounmap);
+EXPORT_SYMBOL(pci_iounmap);
 
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
                    int size, u32 *val)
@@ -483,9 +483,8 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev)
        airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
 }
 
-static void zpci_map_resources(struct zpci_dev *zdev)
+static void zpci_map_resources(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = zdev->pdev;
        resource_size_t len;
        int i;
 
@@ -499,9 +498,8 @@ static void zpci_map_resources(struct zpci_dev *zdev)
        }
 }
 
-static void zpci_unmap_resources(struct zpci_dev *zdev)
+static void zpci_unmap_resources(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = zdev->pdev;
        resource_size_t len;
        int i;
 
@@ -651,7 +649,7 @@ int pcibios_add_device(struct pci_dev *pdev)
 
        zdev->pdev = pdev;
        pdev->dev.groups = zpci_attr_groups;
-       zpci_map_resources(zdev);
+       zpci_map_resources(pdev);
 
        for (i = 0; i < PCI_BAR_COUNT; i++) {
                res = &pdev->resource[i];
@@ -663,6 +661,11 @@ int pcibios_add_device(struct pci_dev *pdev)
        return 0;
 }
 
+void pcibios_release_device(struct pci_dev *pdev)
+{
+       zpci_unmap_resources(pdev);
+}
+
 int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
@@ -670,7 +673,6 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
        zdev->pdev = pdev;
        zpci_debug_init_device(zdev);
        zpci_fmb_enable_device(zdev);
-       zpci_map_resources(zdev);
 
        return pci_enable_resources(pdev, mask);
 }
@@ -679,7 +681,6 @@ void pcibios_disable_device(struct pci_dev *pdev)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
 
-       zpci_unmap_resources(zdev);
        zpci_fmb_disable_device(zdev);
        zpci_debug_exit_device(zdev);
        zdev->pdev = NULL;
@@ -688,7 +689,8 @@ void pcibios_disable_device(struct pci_dev *pdev)
 #ifdef CONFIG_HIBERNATE_CALLBACKS
 static int zpci_restore(struct device *dev)
 {
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct zpci_dev *zdev = get_zdev(pdev);
        int ret = 0;
 
        if (zdev->state != ZPCI_FN_STATE_ONLINE)
@@ -698,7 +700,7 @@ static int zpci_restore(struct device *dev)
        if (ret)
                goto out;
 
-       zpci_map_resources(zdev);
+       zpci_map_resources(pdev);
        zpci_register_ioat(zdev, 0, zdev->start_dma + PAGE_OFFSET,
                           zdev->start_dma + zdev->iommu_size - 1,
                           (u64) zdev->dma_table);
@@ -709,12 +711,14 @@ out:
 
 static int zpci_freeze(struct device *dev)
 {
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct zpci_dev *zdev = get_zdev(pdev);
 
        if (zdev->state != ZPCI_FN_STATE_ONLINE)
                return 0;
 
        zpci_unregister_ioat(zdev, 0);
+       zpci_unmap_resources(pdev);
        return clp_disable_fh(zdev);
 }
 
index 8aa271b..b1bb2b7 100644 (file)
@@ -64,8 +64,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
        if (copy_from_user(buf, user_buffer, length))
                goto out;
 
-       memcpy_toio(io_addr, buf, length);
-       ret = 0;
+       ret = zpci_memcpy_toio(io_addr, buf, length);
 out:
        if (buf != local_buf)
                kfree(buf);
@@ -98,16 +97,16 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
                goto out;
        io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
 
-       ret = -EFAULT;
-       if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
+       if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) {
+               ret = -EFAULT;
                goto out;
-
-       memcpy_fromio(buf, io_addr, length);
-
-       if (copy_to_user(user_buffer, buf, length))
+       }
+       ret = zpci_memcpy_fromio(buf, io_addr, length);
+       if (ret)
                goto out;
+       if (copy_to_user(user_buffer, buf, length))
+               ret = -EFAULT;
 
-       ret = 0;
 out:
        if (buf != local_buf)
                kfree(buf);
index 96ac69c..efb00ec 100644 (file)
@@ -86,6 +86,9 @@ config ARCH_DEFCONFIG
        default "arch/sparc/configs/sparc32_defconfig" if SPARC32
        default "arch/sparc/configs/sparc64_defconfig" if SPARC64
 
+config ARCH_PROC_KCORE_TEXT
+       def_bool y
+
 config IOMMU_HELPER
        bool
        default y if SPARC64
index 4f6725f..f5b6537 100644 (file)
@@ -2957,6 +2957,17 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
                                   unsigned long reg_val);
 #endif
 
+
+#define HV_FAST_M7_GET_PERFREG 0x43
+#define HV_FAST_M7_SET_PERFREG 0x44
+
+#ifndef        __ASSEMBLY__
+unsigned long sun4v_m7_get_perfreg(unsigned long reg_num,
+                                     unsigned long *reg_val);
+unsigned long sun4v_m7_set_perfreg(unsigned long reg_num,
+                                     unsigned long reg_val);
+#endif
+
 /* Function numbers for HV_CORE_TRAP.  */
 #define HV_CORE_SET_VER                        0x00
 #define HV_CORE_PUTCHAR                        0x01
@@ -2981,6 +2992,7 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
 #define HV_GRP_SDIO                    0x0108
 #define HV_GRP_SDIO_ERR                        0x0109
 #define HV_GRP_REBOOT_DATA             0x0110
+#define HV_GRP_M7_PERF                 0x0114
 #define HV_GRP_NIAG_PERF               0x0200
 #define HV_GRP_FIRE_PERF               0x0201
 #define HV_GRP_N2_CPU                  0x0202
index 9b672be..50d4840 100644 (file)
@@ -407,16 +407,16 @@ static inline void iounmap(volatile void __iomem *addr)
 {
 }
 
-#define ioread8(X)                     readb(X)
-#define ioread16(X)                    readw(X)
-#define ioread16be(X)                  __raw_readw(X)
-#define ioread32(X)                    readl(X)
-#define ioread32be(X)                  __raw_readl(X)
-#define iowrite8(val,X)                        writeb(val,X)
-#define iowrite16(val,X)               writew(val,X)
-#define iowrite16be(val,X)             __raw_writew(val,X)
-#define iowrite32(val,X)               writel(val,X)
-#define iowrite32be(val,X)             __raw_writel(val,X)
+#define ioread8                        readb
+#define ioread16               readw
+#define ioread16be             __raw_readw
+#define ioread32               readl
+#define ioread32be             __raw_readl
+#define iowrite8               writeb
+#define iowrite16              writew
+#define iowrite16be            __raw_writew
+#define iowrite32              writel
+#define iowrite32be            __raw_writel
 
 /* Create a virtual mapping cookie for an IO port range */
 void __iomem *ioport_map(unsigned long port, unsigned int nr);
index c100dc2..176fa0a 100644 (file)
@@ -12,7 +12,6 @@
 extern int this_is_starfire;
 
 void check_if_starfire(void);
-int starfire_hard_smp_processor_id(void);
 void starfire_hookup(int);
 unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
 
index 88d322b..07cc49e 100644 (file)
@@ -98,11 +98,7 @@ void sun4v_do_mna(struct pt_regs *regs,
 void do_privop(struct pt_regs *regs);
 void do_privact(struct pt_regs *regs);
 void do_cee(struct pt_regs *regs);
-void do_cee_tl1(struct pt_regs *regs);
-void do_dae_tl1(struct pt_regs *regs);
-void do_iae_tl1(struct pt_regs *regs);
 void do_div0_tl1(struct pt_regs *regs);
-void do_fpdis_tl1(struct pt_regs *regs);
 void do_fpieee_tl1(struct pt_regs *regs);
 void do_fpother_tl1(struct pt_regs *regs);
 void do_ill_tl1(struct pt_regs *regs);
index 5c55145..662500f 100644 (file)
@@ -48,6 +48,7 @@ static struct api_info api_table[] = {
        { .group = HV_GRP_VT_CPU,                               },
        { .group = HV_GRP_T5_CPU,                               },
        { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
+       { .group = HV_GRP_M7_PERF,                              },
 };
 
 static DEFINE_SPINLOCK(hvapi_lock);
index caedf83..afbaba5 100644 (file)
@@ -837,3 +837,19 @@ ENTRY(sun4v_t5_set_perfreg)
        retl
         nop
 ENDPROC(sun4v_t5_set_perfreg)
+
+ENTRY(sun4v_m7_get_perfreg)
+       mov     %o1, %o4
+       mov     HV_FAST_M7_GET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       stx     %o1, [%o4]
+       retl
+       nop
+ENDPROC(sun4v_m7_get_perfreg)
+
+ENTRY(sun4v_m7_set_perfreg)
+       mov     HV_FAST_M7_SET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       retl
+       nop
+ENDPROC(sun4v_m7_set_perfreg)
index 7e967c8..eb978c7 100644 (file)
@@ -217,6 +217,31 @@ static const struct pcr_ops n5_pcr_ops = {
        .pcr_nmi_disable        = PCR_N4_PICNPT,
 };
 
+static u64 m7_pcr_read(unsigned long reg_num)
+{
+       unsigned long val;
+
+       (void) sun4v_m7_get_perfreg(reg_num, &val);
+
+       return val;
+}
+
+static void m7_pcr_write(unsigned long reg_num, u64 val)
+{
+       (void) sun4v_m7_set_perfreg(reg_num, val);
+}
+
+static const struct pcr_ops m7_pcr_ops = {
+       .read_pcr               = m7_pcr_read,
+       .write_pcr              = m7_pcr_write,
+       .read_pic               = n4_pic_read,
+       .write_pic              = n4_pic_write,
+       .nmi_picl_value         = n4_picl_value,
+       .pcr_nmi_enable         = (PCR_N4_PICNPT | PCR_N4_STRACE |
+                                  PCR_N4_UTRACE | PCR_N4_TOE |
+                                  (26 << PCR_N4_SL_SHIFT)),
+       .pcr_nmi_disable        = PCR_N4_PICNPT,
+};
 
 static unsigned long perf_hsvc_group;
 static unsigned long perf_hsvc_major;
@@ -248,6 +273,10 @@ static int __init register_perf_hsvc(void)
                        perf_hsvc_group = HV_GRP_T5_CPU;
                        break;
 
+               case SUN4V_CHIP_SPARC_M7:
+                       perf_hsvc_group = HV_GRP_M7_PERF;
+                       break;
+
                default:
                        return -ENODEV;
                }
@@ -293,6 +322,10 @@ static int __init setup_sun4v_pcr_ops(void)
                pcr_ops = &n5_pcr_ops;
                break;
 
+       case SUN4V_CHIP_SPARC_M7:
+               pcr_ops = &m7_pcr_ops;
+               break;
+
        default:
                ret = -ENODEV;
                break;
index 46a5e45..86eebfa 100644 (file)
@@ -792,6 +792,42 @@ static const struct sparc_pmu niagara4_pmu = {
        .num_pic_regs   = 4,
 };
 
+static void sparc_m7_write_pmc(int idx, u64 val)
+{
+       u64 pcr;
+
+       pcr = pcr_ops->read_pcr(idx);
+       /* ensure ov and ntc are reset */
+       pcr &= ~(PCR_N4_OV | PCR_N4_NTC);
+
+       pcr_ops->write_pic(idx, val & 0xffffffff);
+
+       pcr_ops->write_pcr(idx, pcr);
+}
+
+static const struct sparc_pmu sparc_m7_pmu = {
+       .event_map      = niagara4_event_map,
+       .cache_map      = &niagara4_cache_map,
+       .max_events     = ARRAY_SIZE(niagara4_perfmon_event_map),
+       .read_pmc       = sparc_vt_read_pmc,
+       .write_pmc      = sparc_m7_write_pmc,
+       .upper_shift    = 5,
+       .lower_shift    = 5,
+       .event_mask     = 0x7ff,
+       .user_bit       = PCR_N4_UTRACE,
+       .priv_bit       = PCR_N4_STRACE,
+
+       /* We explicitly don't support hypervisor tracing. */
+       .hv_bit         = 0,
+
+       .irq_bit        = PCR_N4_TOE,
+       .upper_nop      = 0,
+       .lower_nop      = 0,
+       .flags          = 0,
+       .max_hw_events  = 4,
+       .num_pcrs       = 4,
+       .num_pic_regs   = 4,
+};
 static const struct sparc_pmu *sparc_pmu __read_mostly;
 
 static u64 event_encoding(u64 event_id, int idx)
@@ -960,6 +996,8 @@ out:
        cpuc->pcr[0] |= cpuc->event[0]->hw.config_base;
 }
 
+static void sparc_pmu_start(struct perf_event *event, int flags);
+
 /* On this PMU each PIC has it's own PCR control register.  */
 static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
 {
@@ -972,20 +1010,13 @@ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
                struct perf_event *cp = cpuc->event[i];
                struct hw_perf_event *hwc = &cp->hw;
                int idx = hwc->idx;
-               u64 enc;
 
                if (cpuc->current_idx[i] != PIC_NO_INDEX)
                        continue;
 
-               sparc_perf_event_set_period(cp, hwc, idx);
                cpuc->current_idx[i] = idx;
 
-               enc = perf_event_get_enc(cpuc->events[i]);
-               cpuc->pcr[idx] &= ~mask_for_index(idx);
-               if (hwc->state & PERF_HES_STOPPED)
-                       cpuc->pcr[idx] |= nop_for_index(idx);
-               else
-                       cpuc->pcr[idx] |= event_encoding(enc, idx);
+               sparc_pmu_start(cp, PERF_EF_RELOAD);
        }
 out:
        for (i = 0; i < cpuc->n_events; i++) {
@@ -1101,7 +1132,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags)
        int i;
 
        local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
 
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event[i]) {
@@ -1127,7 +1157,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags)
                }
        }
 
-       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
 }
 
@@ -1361,7 +1390,6 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags)
        unsigned long flags;
 
        local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
 
        n0 = cpuc->n_events;
        if (n0 >= sparc_pmu->max_hw_events)
@@ -1394,7 +1422,6 @@ nocheck:
 
        ret = 0;
 out:
-       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
        return ret;
 }
@@ -1667,6 +1694,10 @@ static bool __init supported_pmu(void)
                sparc_pmu = &niagara4_pmu;
                return true;
        }
+       if (!strcmp(sparc_pmu_type, "sparc-m7")) {
+               sparc_pmu = &sparc_m7_pmu;
+               return true;
+       }
        return false;
 }
 
index 0be7bf9..46a5964 100644 (file)
@@ -287,6 +287,8 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
                        printk("             TPC[%lx] O7[%lx] I7[%lx] RPC[%lx]\n",
                               gp->tpc, gp->o7, gp->i7, gp->rpc);
                }
+
+               touch_nmi_watchdog();
        }
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
@@ -362,6 +364,8 @@ static void pmu_snapshot_all_cpus(void)
                       (cpu == this_cpu ? '*' : ' '), cpu,
                       pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3],
                       pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]);
+
+               touch_nmi_watchdog();
        }
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
index da6f1a7..61139d9 100644 (file)
@@ -1406,11 +1406,32 @@ void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
        scheduler_ipi();
 }
 
-/* This is a nop because we capture all other cpus
- * anyways when making the PROM active.
- */
+static void stop_this_cpu(void *dummy)
+{
+       prom_stopself();
+}
+
 void smp_send_stop(void)
 {
+       int cpu;
+
+       if (tlb_type == hypervisor) {
+               for_each_online_cpu(cpu) {
+                       if (cpu == smp_processor_id())
+                               continue;
+#ifdef CONFIG_SUN_LDOMS
+                       if (ldom_domaining_enabled) {
+                               unsigned long hv_err;
+                               hv_err = sun4v_cpu_stop(cpu);
+                               if (hv_err)
+                                       printk(KERN_ERR "sun4v_cpu_stop() "
+                                              "failed err=%lu\n", hv_err);
+                       } else
+#endif
+                               prom_stopcpu_cpuid(cpu);
+               }
+       } else
+               smp_call_function(stop_this_cpu, NULL, 0);
 }
 
 /**
index 82281a5..167fdfd 100644 (file)
@@ -28,11 +28,6 @@ void check_if_starfire(void)
                this_is_starfire = 1;
 }
 
-int starfire_hard_smp_processor_id(void)
-{
-       return upa_readl(0x1fff40000d0UL);
-}
-
 /*
  * Each Starfire board has 32 registers which perform translation
  * and delivery of traditional interrupt packets into the extended
index c85403d..30e7ddb 100644 (file)
@@ -333,7 +333,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
        long err;
 
        /* No need for backward compatibility. We can start fresh... */
-       if (call <= SEMCTL) {
+       if (call <= SEMTIMEDOP) {
                switch (call) {
                case SEMOP:
                        err = sys_semtimedop(first, ptr,
index a27651e..0e69974 100644 (file)
@@ -2427,6 +2427,8 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs)
                }
                user_instruction_dump ((unsigned int __user *) regs->tpc);
        }
+       if (panic_on_oops)
+               panic("Fatal exception");
        if (regs->tstate & TSTATE_PRIV)
                do_exit(SIGKILL);
        do_exit(SIGSEGV);
@@ -2564,27 +2566,6 @@ void do_cee(struct pt_regs *regs)
        die_if_kernel("TL0: Cache Error Exception", regs);
 }
 
-void do_cee_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Cache Error Exception", regs);
-}
-
-void do_dae_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Data Access Exception", regs);
-}
-
-void do_iae_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Instruction Access Exception", regs);
-}
-
 void do_div0_tl1(struct pt_regs *regs)
 {
        exception_enter();
@@ -2592,13 +2573,6 @@ void do_div0_tl1(struct pt_regs *regs)
        die_if_kernel("TL1: DIV0 Exception", regs);
 }
 
-void do_fpdis_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: FPU Disabled", regs);
-}
-
 void do_fpieee_tl1(struct pt_regs *regs)
 {
        exception_enter();
index b7f6334..857ad4f 100644 (file)
@@ -8,9 +8,11 @@
 
        .text
 ENTRY(memmove) /* o0=dst o1=src o2=len */
-       mov             %o0, %g1
+       brz,pn          %o2, 99f
+        mov            %o0, %g1
+
        cmp             %o0, %o1
-       bleu,pt         %xcc, memcpy
+       bleu,pt         %xcc, 2f
         add            %o1, %o2, %g7
        cmp             %g7, %o0
        bleu,pt         %xcc, memcpy
@@ -24,7 +26,34 @@ ENTRY(memmove) /* o0=dst o1=src o2=len */
        stb             %g7, [%o0]
        bne,pt          %icc, 1b
         sub            %o0, 1, %o0
-
+99:
        retl
         mov            %g1, %o0
+
+       /* We can't just call memcpy for these memmove cases.  On some
+        * chips the memcpy uses cache initializing stores and when dst
+        * and src are close enough, those can clobber the source data
+        * before we've loaded it in.
+        */
+2:     or              %o0, %o1, %g7
+       or              %o2, %g7, %g7
+       andcc           %g7, 0x7, %g0
+       bne,pn          %xcc, 4f
+        nop
+
+3:     ldx             [%o1], %g7
+       add             %o1, 8, %o1
+       subcc           %o2, 8, %o2
+       add             %o0, 8, %o0
+       bne,pt          %icc, 3b
+        stx            %g7, [%o0 - 0x8]
+       ba,a,pt         %xcc, 99b
+
+4:     ldub            [%o1], %g7
+       add             %o1, 1, %o1
+       subcc           %o2, 1, %o2
+       add             %o0, 1, %o0
+       bne,pt          %icc, 4b
+        stb            %g7, [%o0 - 0x1]
+       ba,a,pt         %xcc, 99b
 ENDPROC(memmove)
index 3ea267c..4ca0d6b 100644 (file)
@@ -2820,7 +2820,7 @@ static int __init report_memory(void)
 
        return 0;
 }
-device_initcall(report_memory);
+arch_initcall(report_memory);
 
 #ifdef CONFIG_SMP
 #define do_flush_tlb_kernel_range      smp_flush_tlb_kernel_range
index c2fb8a8..b7d31ca 100644 (file)
@@ -499,6 +499,7 @@ config X86_INTEL_QUARK
        depends on X86_IO_APIC
        select IOSF_MBI
        select INTEL_IMR
+       select COMMON_CLK
        ---help---
          Select to include support for Quark X1000 SoC.
          Say Y here if you have a Quark based system such as the Arduino
index 7083c16..bb13763 100644 (file)
 static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
                LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
 
-struct kaslr_setup_data {
-       __u64 next;
-       __u32 type;
-       __u32 len;
-       __u8 data[1];
-} kaslr_setup_data;
-
 #define I8254_PORT_CONTROL     0x43
 #define I8254_PORT_COUNTER0    0x40
 #define I8254_CMD_READBACK     0xC0
@@ -302,29 +295,7 @@ static unsigned long find_random_addr(unsigned long minimum,
        return slots_fetch_random();
 }
 
-static void add_kaslr_setup_data(struct boot_params *params, __u8 enabled)
-{
-       struct setup_data *data;
-
-       kaslr_setup_data.type = SETUP_KASLR;
-       kaslr_setup_data.len = 1;
-       kaslr_setup_data.next = 0;
-       kaslr_setup_data.data[0] = enabled;
-
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
-
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
-
-       if (data)
-               data->next = (unsigned long)&kaslr_setup_data;
-       else
-               params->hdr.setup_data = (unsigned long)&kaslr_setup_data;
-
-}
-
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size)
@@ -335,17 +306,14 @@ unsigned char *choose_kernel_location(struct boot_params *params,
 #ifdef CONFIG_HIBERNATION
        if (!cmdline_find_option_bool("kaslr")) {
                debug_putstr("KASLR disabled by default...\n");
-               add_kaslr_setup_data(params, 0);
                goto out;
        }
 #else
        if (cmdline_find_option_bool("nokaslr")) {
                debug_putstr("KASLR disabled by cmdline...\n");
-               add_kaslr_setup_data(params, 0);
                goto out;
        }
 #endif
-       add_kaslr_setup_data(params, 1);
 
        /* Record the various known unsafe memory ranges. */
        mem_avoid_init((unsigned long)input, input_size,
index 5903089..a950864 100644 (file)
@@ -401,8 +401,7 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
         * the entire decompressed kernel plus relocation table, or the
         * entire decompressed kernel plus .bss and .brk sections.
         */
-       output = choose_kernel_location(real_mode, input_data, input_len,
-                                       output,
+       output = choose_kernel_location(input_data, input_len, output,
                                        output_len > run_size ? output_len
                                                              : run_size);
 
index ee3576b..04477d6 100644 (file)
@@ -57,8 +57,7 @@ int cmdline_find_option_bool(const char *option);
 
 #if CONFIG_RANDOMIZE_BASE
 /* aslr.c */
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size);
@@ -66,8 +65,7 @@ unsigned char *choose_kernel_location(struct boot_params *params,
 bool has_cpuflag(int flag);
 #else
 static inline
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size)
index 947c6bf..54f60ab 100644 (file)
@@ -1155,7 +1155,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
                src = kmalloc(req->cryptlen + req->assoclen, GFP_ATOMIC);
                if (!src)
                        return -ENOMEM;
-               assoc = (src + req->cryptlen + auth_tag_len);
+               assoc = (src + req->cryptlen);
                scatterwalk_map_and_copy(src, req->src, 0, req->cryptlen, 0);
                scatterwalk_map_and_copy(assoc, req->assoc, 0,
                        req->assoclen, 0);
@@ -1180,7 +1180,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
                scatterwalk_done(&src_sg_walk, 0, 0);
                scatterwalk_done(&assoc_sg_walk, 0, 0);
        } else {
-               scatterwalk_map_and_copy(dst, req->dst, 0, req->cryptlen, 1);
+               scatterwalk_map_and_copy(dst, req->dst, 0, tempCipherLen, 1);
                kfree(src);
        }
        return retval;
index 0dbc082..72ba21a 100644 (file)
@@ -370,7 +370,7 @@ static inline void drop_fpu(struct task_struct *tsk)
        preempt_disable();
        tsk->thread.fpu_counter = 0;
        __drop_fpu(tsk);
-       clear_used_math();
+       clear_stopped_child_used_math(tsk);
        preempt_enable();
 }
 
index 95e11f7..f97fbe3 100644 (file)
@@ -51,8 +51,6 @@ extern int devmem_is_allowed(unsigned long pagenr);
 extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
 
-extern bool kaslr_enabled;
-
 static inline phys_addr_t get_max_mapped(void)
 {
        return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
index fa1195d..164e3f8 100644 (file)
@@ -93,6 +93,8 @@ extern raw_spinlock_t pci_config_lock;
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
 extern void (*pcibios_disable_irq)(struct pci_dev *dev);
 
+extern bool mp_should_keep_irq(struct device *dev);
+
 struct pci_raw_ops {
        int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
                                                int reg, int len, u32 *val);
index 5fa9770..c9a6d68 100644 (file)
@@ -82,18 +82,15 @@ static inline int xsave_state_booting(struct xsave_struct *fx, u64 mask)
        if (boot_cpu_has(X86_FEATURE_XSAVES))
                asm volatile("1:"XSAVES"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
        else
                asm volatile("1:"XSAVE"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
-
-       asm volatile(xstate_fault
-                    : "0" (0)
-                    : "memory");
-
        return err;
 }
 
@@ -112,18 +109,15 @@ static inline int xrstor_state_booting(struct xsave_struct *fx, u64 mask)
        if (boot_cpu_has(X86_FEATURE_XSAVES))
                asm volatile("1:"XRSTORS"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
        else
                asm volatile("1:"XRSTOR"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
-
-       asm volatile(xstate_fault
-                    : "0" (0)
-                    : "memory");
-
        return err;
 }
 
@@ -149,9 +143,9 @@ static inline int xsave_state(struct xsave_struct *fx, u64 mask)
         */
        alternative_input_2(
                "1:"XSAVE,
-               "1:"XSAVEOPT,
+               XSAVEOPT,
                X86_FEATURE_XSAVEOPT,
-               "1:"XSAVES,
+               XSAVES,
                X86_FEATURE_XSAVES,
                [fx] "D" (fx), "a" (lmask), "d" (hmask) :
                "memory");
@@ -178,7 +172,7 @@ static inline int xrstor_state(struct xsave_struct *fx, u64 mask)
         */
        alternative_input(
                "1: " XRSTOR,
-               "1: " XRSTORS,
+               XRSTORS,
                X86_FEATURE_XSAVES,
                "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                : "memory");
index 44e6dd7..225b098 100644 (file)
@@ -7,7 +7,6 @@
 #define SETUP_DTB                      2
 #define SETUP_PCI                      3
 #define SETUP_EFI                      4
-#define SETUP_KASLR                    5
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
index 3d525c6..803b684 100644 (file)
@@ -1337,6 +1337,26 @@ static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
        return 0;
 }
 
+/*
+ * ACPI offers an alternative platform interface model that removes
+ * ACPI hardware requirements for platforms that do not implement
+ * the PC Architecture.
+ *
+ * We initialize the Hardware-reduced ACPI model here:
+ */
+static void __init acpi_reduced_hw_init(void)
+{
+       if (acpi_gbl_reduced_hardware) {
+               /*
+                * Override x86_init functions and bypass legacy pic
+                * in Hardware-reduced ACPI mode
+                */
+               x86_init.timers.timer_init      = x86_init_noop;
+               x86_init.irqs.pre_vector_init   = x86_init_noop;
+               legacy_pic                      = &null_legacy_pic;
+       }
+}
+
 /*
  * If your system is blacklisted here, but you find that acpi=force
  * works for you, please contact linux-acpi@vger.kernel.org
@@ -1536,6 +1556,11 @@ int __init early_acpi_boot_init(void)
         */
        early_acpi_process_madt();
 
+       /*
+        * Hardware-reduced ACPI mode initialization:
+        */
+       acpi_reduced_hw_init();
+
        return 0;
 }
 
index c2fd21f..017149c 100644 (file)
@@ -37,10 +37,12 @@ static const struct apic apic_numachip;
 static unsigned int get_apic_id(unsigned long x)
 {
        unsigned long value;
-       unsigned int id;
+       unsigned int id = (x >> 24) & 0xff;
 
-       rdmsrl(MSR_FAM10H_NODE_ID, value);
-       id = ((x >> 24) & 0xffU) | ((value << 2) & 0xff00U);
+       if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+               rdmsrl(MSR_FAM10H_NODE_ID, value);
+               id |= (value << 2) & 0xff00;
+       }
 
        return id;
 }
@@ -155,10 +157,18 @@ static int __init numachip_probe(void)
 
 static void fixup_cpu_id(struct cpuinfo_x86 *c, int node)
 {
-       if (c->phys_proc_id != node) {
-               c->phys_proc_id = node;
-               per_cpu(cpu_llc_id, smp_processor_id()) = node;
+       u64 val;
+       u32 nodes = 1;
+
+       this_cpu_write(cpu_llc_id, node);
+
+       /* Account for nodes per socket in multi-core-module processors */
+       if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+               rdmsrl(MSR_FAM10H_NODE_ID, val);
+               nodes = ((val >> 3) & 7) + 1;
        }
+
+       c->phys_proc_id = node / nodes;
 }
 
 static int __init numachip_system_init(void)
index b5c8ff5..2346c95 100644 (file)
@@ -1396,6 +1396,12 @@ void cpu_init(void)
 
        wait_for_master_cpu(cpu);
 
+       /*
+        * Initialize the CR4 shadow before doing anything that could
+        * try to read it.
+        */
+       cr4_init_shadow();
+
        show_ucode_info_early();
 
        printk(KERN_INFO "Initializing CPU#%d\n", cpu);
index 94d7dcb..50163fa 100644 (file)
@@ -565,8 +565,8 @@ static const struct _tlb_table intel_tlb_table[] = {
        { 0xb2, TLB_INST_4K,            64,     " TLB_INST 4KByte pages, 4-way set associative" },
        { 0xb3, TLB_DATA_4K,            128,    " TLB_DATA 4 KByte pages, 4-way set associative" },
        { 0xb4, TLB_DATA_4K,            256,    " TLB_DATA 4 KByte pages, 4-way associative" },
-       { 0xb5, TLB_INST_4K,            64,     " TLB_INST 4 KByte pages, 8-way set ssociative" },
-       { 0xb6, TLB_INST_4K,            128,    " TLB_INST 4 KByte pages, 8-way set ssociative" },
+       { 0xb5, TLB_INST_4K,            64,     " TLB_INST 4 KByte pages, 8-way set associative" },
+       { 0xb6, TLB_INST_4K,            128,    " TLB_INST 4 KByte pages, 8-way set associative" },
        { 0xba, TLB_DATA_4K,            64,     " TLB_DATA 4 KByte pages, 4-way associative" },
        { 0xc0, TLB_DATA_4K_4M,         8,      " TLB_DATA 4 KByte and 4 MByte pages, 4-way associative" },
        { 0xc1, STLB_4K_2M,             1024,   " STLB 4 KByte and 2 MByte pages, 8-way associative" },
index 498b6d9..2589906 100644 (file)
@@ -212,11 +212,11 @@ static struct event_constraint intel_hsw_event_constraints[] = {
        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
        INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
        /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
-       INTEL_EVENT_CONSTRAINT(0x08a3, 0x4),
+       INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4),
        /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */
-       INTEL_EVENT_CONSTRAINT(0x0ca3, 0x4),
+       INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4),
        /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */
-       INTEL_EVENT_CONSTRAINT(0x04a3, 0xf),
+       INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf),
        EVENT_CONSTRAINT_END
 };
 
@@ -1649,11 +1649,11 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event
        if (c)
                return c;
 
-       c = intel_pebs_constraints(event);
+       c = intel_shared_regs_constraints(cpuc, event);
        if (c)
                return c;
 
-       c = intel_shared_regs_constraints(cpuc, event);
+       c = intel_pebs_constraints(event);
        if (c)
                return c;
 
index 000d419..31e2d5b 100644 (file)
@@ -982,6 +982,9 @@ ENTRY(xen_hypervisor_callback)
 ENTRY(xen_do_upcall)
 1:     mov %esp, %eax
        call xen_evtchn_do_upcall
+#ifndef CONFIG_PREEMPT
+       call xen_maybe_preempt_hcall
+#endif
        jmp  ret_from_intr
        CFI_ENDPROC
 ENDPROC(xen_hypervisor_callback)
index db13655..f0095a7 100644 (file)
@@ -269,11 +269,14 @@ ENTRY(ret_from_fork)
        testl $3, CS-ARGOFFSET(%rsp)            # from kernel_thread?
        jz   1f
 
-       testl $_TIF_IA32, TI_flags(%rcx)        # 32-bit compat task needs IRET
-       jnz  int_ret_from_sys_call
-
-       RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET
-       jmp ret_from_sys_call                   # go to the SYSRET fastpath
+       /*
+        * By the time we get here, we have no idea whether our pt_regs,
+        * ti flags, and ti status came from the 64-bit SYSCALL fast path,
+        * the slow path, or one of the ia32entry paths.
+        * Use int_ret_from_sys_call to return, since it can safely handle
+        * all of the above.
+        */
+       jmp  int_ret_from_sys_call
 
 1:
        subq $REST_SKIP, %rsp   # leave space for volatiles
@@ -361,12 +364,21 @@ system_call_fastpath:
  * Has incomplete stack frame and undefined top of stack.
  */
 ret_from_sys_call:
-       testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
-       jnz int_ret_from_sys_call_fixup /* Go the the slow path */
-
        LOCKDEP_SYS_EXIT
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
+
+       /*
+        * We must check ti flags with interrupts (or at least preemption)
+        * off because we must *never* return to userspace without
+        * processing exit work that is enqueued if we're preempted here.
+        * In particular, returning to userspace with any of the one-shot
+        * flags (TIF_NOTIFY_RESUME, TIF_USER_RETURN_NOTIFY, etc) set is
+        * very bad.
+        */
+       testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
+       jnz int_ret_from_sys_call_fixup /* Go the the slow path */
+
        CFI_REMEMBER_STATE
        /*
         * sysretq will re-enable interrupts:
@@ -383,7 +395,7 @@ ret_from_sys_call:
 
 int_ret_from_sys_call_fixup:
        FIXUP_TOP_OF_STACK %r11, -ARGOFFSET
-       jmp int_ret_from_sys_call
+       jmp int_ret_from_sys_call_irqs_off
 
        /* Do syscall tracing */
 tracesys:
@@ -429,6 +441,7 @@ tracesys_phase2:
 GLOBAL(int_ret_from_sys_call)
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
+int_ret_from_sys_call_irqs_off:
        movl $_TIF_ALLWORK_MASK,%edi
        /* edi: mask to check */
 GLOBAL(int_with_check)
@@ -786,7 +799,21 @@ retint_swapgs:             /* return to user-space */
        cmpq %r11,(EFLAGS-ARGOFFSET)(%rsp)      /* R11 == RFLAGS */
        jne opportunistic_sysret_failed
 
-       testq $X86_EFLAGS_RF,%r11               /* sysret can't restore RF */
+       /*
+        * SYSRET can't restore RF.  SYSRET can restore TF, but unlike IRET,
+        * restoring TF results in a trap from userspace immediately after
+        * SYSRET.  This would cause an infinite loop whenever #DB happens
+        * with register state that satisfies the opportunistic SYSRET
+        * conditions.  For example, single-stepping this user code:
+        *
+        *           movq $stuck_here,%rcx
+        *           pushfq
+        *           popq %r11
+        *   stuck_here:
+        *
+        * would never get past 'stuck_here'.
+        */
+       testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
        jnz opportunistic_sysret_failed
 
        /* nothing to check for RSP */
@@ -1208,6 +1235,9 @@ ENTRY(xen_do_hypervisor_callback)   # do_hypervisor_callback(struct *pt_regs)
        popq %rsp
        CFI_DEF_CFA_REGISTER rsp
        decl PER_CPU_VAR(irq_count)
+#ifndef CONFIG_PREEMPT
+       call xen_maybe_preempt_hcall
+#endif
        jmp  error_exit
        CFI_ENDPROC
 END(xen_do_hypervisor_callback)
index 7ec1d5f..25ecd56 100644 (file)
@@ -72,7 +72,7 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
        { "bx", 8, offsetof(struct pt_regs, bx) },
        { "cx", 8, offsetof(struct pt_regs, cx) },
        { "dx", 8, offsetof(struct pt_regs, dx) },
-       { "si", 8, offsetof(struct pt_regs, dx) },
+       { "si", 8, offsetof(struct pt_regs, si) },
        { "di", 8, offsetof(struct pt_regs, di) },
        { "bp", 8, offsetof(struct pt_regs, bp) },
        { "sp", 8, offsetof(struct pt_regs, sp) },
index 6a1146e..4e3d5a9 100644 (file)
@@ -223,27 +223,48 @@ static unsigned long
 __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
 {
        struct kprobe *kp;
+       unsigned long faddr;
 
        kp = get_kprobe((void *)addr);
-       /* There is no probe, return original address */
-       if (!kp)
+       faddr = ftrace_location(addr);
+       /*
+        * Addresses inside the ftrace location are refused by
+        * arch_check_ftrace_location(). Something went terribly wrong
+        * if such an address is checked here.
+        */
+       if (WARN_ON(faddr && faddr != addr))
+               return 0UL;
+       /*
+        * Use the current code if it is not modified by Kprobe
+        * and it cannot be modified by ftrace.
+        */
+       if (!kp && !faddr)
                return addr;
 
        /*
-        *  Basically, kp->ainsn.insn has an original instruction.
-        *  However, RIP-relative instruction can not do single-stepping
-        *  at different place, __copy_instruction() tweaks the displacement of
-        *  that instruction. In that case, we can't recover the instruction
-        *  from the kp->ainsn.insn.
+        * Basically, kp->ainsn.insn has an original instruction.
+        * However, RIP-relative instruction can not do single-stepping
+        * at different place, __copy_instruction() tweaks the displacement of
+        * that instruction. In that case, we can't recover the instruction
+        * from the kp->ainsn.insn.
         *
-        *  On the other hand, kp->opcode has a copy of the first byte of
-        *  the probed instruction, which is overwritten by int3. And
-        *  the instruction at kp->addr is not modified by kprobes except
-        *  for the first byte, we can recover the original instruction
-        *  from it and kp->opcode.
+        * On the other hand, in case on normal Kprobe, kp->opcode has a copy
+        * of the first byte of the probed instruction, which is overwritten
+        * by int3. And the instruction at kp->addr is not modified by kprobes
+        * except for the first byte, we can recover the original instruction
+        * from it and kp->opcode.
+        *
+        * In case of Kprobes using ftrace, we do not have a copy of
+        * the original instruction. In fact, the ftrace location might
+        * be modified at anytime and even could be in an inconsistent state.
+        * Fortunately, we know that the original code is the ideal 5-byte
+        * long NOP.
         */
-       memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
-       buf[0] = kp->opcode;
+       memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+       if (faddr)
+               memcpy(buf, ideal_nops[NOP_ATOMIC5], 5);
+       else
+               buf[0] = kp->opcode;
        return (unsigned long)buf;
 }
 
@@ -251,6 +272,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
  * Recover the probed instruction at addr for further analysis.
  * Caller must lock kprobes by kprobe_mutex, or disable preemption
  * for preventing to release referencing kprobes.
+ * Returns zero if the instruction can not get recovered.
  */
 unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
 {
@@ -285,6 +307,8 @@ static int can_probe(unsigned long paddr)
                 * normally used, we just go through if there is no kprobe.
                 */
                __addr = recover_probed_instruction(buf, addr);
+               if (!__addr)
+                       return 0;
                kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE);
                insn_get_length(&insn);
 
@@ -333,6 +357,8 @@ int __copy_instruction(u8 *dest, u8 *src)
        unsigned long recovered_insn =
                recover_probed_instruction(buf, (unsigned long)src);
 
+       if (!recovered_insn)
+               return 0;
        kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
        insn_get_length(&insn);
        /* Another subsystem puts a breakpoint, failed to recover */
index 0dd8d08..7b3b9d1 100644 (file)
@@ -259,6 +259,8 @@ static int can_optimize(unsigned long paddr)
                         */
                        return 0;
                recovered_insn = recover_probed_instruction(buf, addr);
+               if (!recovered_insn)
+                       return 0;
                kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
                insn_get_length(&insn);
                /* Another subsystem puts a breakpoint */
index 9bbb9b3..d1ac80b 100644 (file)
@@ -47,13 +47,21 @@ do {                                                        \
 
 #ifdef CONFIG_RANDOMIZE_BASE
 static unsigned long module_load_offset;
+static int randomize_modules = 1;
 
 /* Mutex protects the module_load_offset. */
 static DEFINE_MUTEX(module_kaslr_mutex);
 
+static int __init parse_nokaslr(char *p)
+{
+       randomize_modules = 0;
+       return 0;
+}
+early_param("nokaslr", parse_nokaslr);
+
 static unsigned long int get_module_load_offset(void)
 {
-       if (kaslr_enabled) {
+       if (randomize_modules) {
                mutex_lock(&module_kaslr_mutex);
                /*
                 * Calculate the module_load_offset the first time this
index bae6c60..86db4bc 100644 (file)
@@ -183,6 +183,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                },
        },
 
+       /* ASRock */
+       {       /* Handle problems with rebooting on ASRock Q1900DC-ITX */
+               .callback = set_pci_reboot,
+               .ident = "ASRock Q1900DC-ITX",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASRock"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Q1900DC-ITX"),
+               },
+       },
+
        /* ASUS */
        {       /* Handle problems with rebooting on ASUS P4S800 */
                .callback = set_bios_reboot,
index 98dc931..0a2421c 100644 (file)
 unsigned long max_low_pfn_mapped;
 unsigned long max_pfn_mapped;
 
-bool __read_mostly kaslr_enabled = false;
-
 #ifdef CONFIG_DMI
 RESERVE_BRK(dmi_alloc, 65536);
 #endif
@@ -427,11 +425,6 @@ static void __init reserve_initrd(void)
 }
 #endif /* CONFIG_BLK_DEV_INITRD */
 
-static void __init parse_kaslr_setup(u64 pa_data, u32 data_len)
-{
-       kaslr_enabled = (bool)(pa_data + sizeof(struct setup_data));
-}
-
 static void __init parse_setup_data(void)
 {
        struct setup_data *data;
@@ -457,9 +450,6 @@ static void __init parse_setup_data(void)
                case SETUP_EFI:
                        parse_efi_setup(pa_data, data_len);
                        break;
-               case SETUP_KASLR:
-                       parse_kaslr_setup(pa_data, data_len);
-                       break;
                default:
                        break;
                }
@@ -842,14 +832,10 @@ static void __init trim_low_memory_range(void)
 static int
 dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
 {
-       if (kaslr_enabled)
-               pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n",
-                        (unsigned long)&_text - __START_KERNEL,
-                        __START_KERNEL,
-                        __START_KERNEL_map,
-                        MODULES_VADDR-1);
-       else
-               pr_emerg("Kernel Offset: disabled\n");
+       pr_emerg("Kernel Offset: 0x%lx from 0x%lx "
+                "(relocation range: 0x%lx-0x%lx)\n",
+                (unsigned long)&_text - __START_KERNEL, __START_KERNEL,
+                __START_KERNEL_map, MODULES_VADDR-1);
 
        return 0;
 }
index 9d2073e..4ff5d16 100644 (file)
@@ -384,7 +384,7 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
                goto exit;
        conditional_sti(regs);
 
-       if (!user_mode(regs))
+       if (!user_mode_vm(regs))
                die("bounds", regs, error_code);
 
        if (!cpu_feature_enabled(X86_FEATURE_MPX)) {
@@ -637,7 +637,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
         * then it's very likely the result of an icebp/int01 trap.
         * User wants a sigtrap for that.
         */
-       if (!dr6 && user_mode(regs))
+       if (!dr6 && user_mode_vm(regs))
                user_icebp = 1;
 
        /* Catch kmemcheck conditions first of all! */
index 34f66e5..cdc6cf9 100644 (file)
@@ -379,7 +379,7 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                 * thread's fpu state, reconstruct fxstate from the fsave
                 * header. Sanitize the copied state etc.
                 */
-               struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
+               struct fpu *fpu = &tsk->thread.fpu;
                struct user_i387_ia32_struct env;
                int err = 0;
 
@@ -393,14 +393,15 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                 */
                drop_fpu(tsk);
 
-               if (__copy_from_user(xsave, buf_fx, state_size) ||
+               if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) ||
                    __copy_from_user(&env, buf, sizeof(env))) {
+                       fpu_finit(fpu);
                        err = -1;
                } else {
                        sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
-                       set_used_math();
                }
 
+               set_used_math();
                if (use_eager_fpu()) {
                        preempt_disable();
                        math_state_restore();
index e0b794a..106c015 100644 (file)
@@ -4950,7 +4950,8 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
                        goto done;
                }
        }
-       ctxt->dst.orig_val = ctxt->dst.val;
+       /* Copy full 64-bit value for CMPXCHG8B.  */
+       ctxt->dst.orig_val64 = ctxt->dst.val64;
 
 special_insn:
 
index cc31f7c..9541ba3 100644 (file)
@@ -507,6 +507,7 @@ static int picdev_read(struct kvm_pic *s,
                return -EOPNOTSUPP;
 
        if (len != 1) {
+               memset(val, 0, len);
                pr_pic_unimpl("non byte read\n");
                return 0;
        }
index b1947e0..46d4449 100644 (file)
@@ -422,6 +422,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
                        struct kvm_ioapic *ioapic, int vector, int trigger_mode)
 {
        int i;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        for (i = 0; i < IOAPIC_NUM_PINS; i++) {
                union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
@@ -443,7 +444,8 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
                kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
                spin_lock(&ioapic->lock);
 
-               if (trigger_mode != IOAPIC_LEVEL_TRIG)
+               if (trigger_mode != IOAPIC_LEVEL_TRIG ||
+                   kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
                        continue;
 
                ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
index e55b5fc..4ee827d 100644 (file)
@@ -833,8 +833,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 
 static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
 {
-       if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
-           kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
+       if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
                int trigger_mode;
                if (apic_test_vector(vector, apic->regs + APIC_TMR))
                        trigger_mode = IOAPIC_LEVEL_TRIG;
@@ -1572,7 +1571,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
                apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
        }
        apic->irr_pending = kvm_apic_vid_enabled(vcpu->kvm);
-       apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm);
+       apic->isr_count = kvm_x86_ops->hwapic_isr_update ? 1 : 0;
        apic->highest_isr_cache = -1;
        update_divide_count(apic);
        atomic_set(&apic->lapic_timer.pending, 0);
@@ -1782,7 +1781,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
        update_divide_count(apic);
        start_apic_timer(apic);
        apic->irr_pending = true;
-       apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm) ?
+       apic->isr_count = kvm_x86_ops->hwapic_isr_update ?
                                1 : count_vectors(apic->regs + APIC_ISR);
        apic->highest_isr_cache = -1;
        if (kvm_x86_ops->hwapic_irr_update)
index d319e0c..cc618c8 100644 (file)
@@ -3649,11 +3649,6 @@ static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
        return;
 }
 
-static void svm_hwapic_isr_update(struct kvm *kvm, int isr)
-{
-       return;
-}
-
 static void svm_sync_pir_to_irr(struct kvm_vcpu *vcpu)
 {
        return;
@@ -4403,7 +4398,6 @@ static struct kvm_x86_ops svm_x86_ops = {
        .set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
        .vm_has_apicv = svm_vm_has_apicv,
        .load_eoi_exitmap = svm_load_eoi_exitmap,
-       .hwapic_isr_update = svm_hwapic_isr_update,
        .sync_pir_to_irr = svm_sync_pir_to_irr,
 
        .set_tss_addr = svm_set_tss_addr,
index 14c1a18..ae4f6d3 100644 (file)
@@ -2168,7 +2168,10 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
 {
        unsigned long *msr_bitmap;
 
-       if (irqchip_in_kernel(vcpu->kvm) && apic_x2apic_mode(vcpu->arch.apic)) {
+       if (is_guest_mode(vcpu))
+               msr_bitmap = vmx_msr_bitmap_nested;
+       else if (irqchip_in_kernel(vcpu->kvm) &&
+               apic_x2apic_mode(vcpu->arch.apic)) {
                if (is_long_mode(vcpu))
                        msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
                else
@@ -2476,8 +2479,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        if (enable_ept) {
                /* nested EPT: emulate EPT also to L1 */
                vmx->nested.nested_vmx_secondary_ctls_high |=
-                       SECONDARY_EXEC_ENABLE_EPT |
-                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+                       SECONDARY_EXEC_ENABLE_EPT;
                vmx->nested.nested_vmx_ept_caps = VMX_EPT_PAGE_WALK_4_BIT |
                         VMX_EPTP_WB_BIT | VMX_EPT_2MB_PAGE_BIT |
                         VMX_EPT_INVEPT_BIT;
@@ -2491,6 +2493,10 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        } else
                vmx->nested.nested_vmx_ept_caps = 0;
 
+       if (enable_unrestricted_guest)
+               vmx->nested.nested_vmx_secondary_ctls_high |=
+                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+
        /* miscellaneous data */
        rdmsr(MSR_IA32_VMX_MISC,
                vmx->nested.nested_vmx_misc_low,
@@ -4367,6 +4373,18 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_SMP
+       if (vcpu->mode == IN_GUEST_MODE) {
+               apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
+                               POSTED_INTR_VECTOR);
+               return true;
+       }
+#endif
+       return false;
+}
+
 static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
                                                int vector)
 {
@@ -4375,9 +4393,7 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
        if (is_guest_mode(vcpu) &&
            vector == vmx->nested.posted_intr_nv) {
                /* the PIR and ON have been set by L1. */
-               if (vcpu->mode == IN_GUEST_MODE)
-                       apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
-                               POSTED_INTR_VECTOR);
+               kvm_vcpu_trigger_posted_interrupt(vcpu);
                /*
                 * If a posted intr is not recognized by hardware,
                 * we will accomplish it in the next vmentry.
@@ -4409,12 +4425,7 @@ static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
 
        r = pi_test_and_set_on(&vmx->pi_desc);
        kvm_make_request(KVM_REQ_EVENT, vcpu);
-#ifdef CONFIG_SMP
-       if (!r && (vcpu->mode == IN_GUEST_MODE))
-               apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
-                               POSTED_INTR_VECTOR);
-       else
-#endif
+       if (r || !kvm_vcpu_trigger_posted_interrupt(vcpu))
                kvm_vcpu_kick(vcpu);
 }
 
@@ -9213,9 +9224,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        }
 
        if (cpu_has_vmx_msr_bitmap() &&
-           exec_control & CPU_BASED_USE_MSR_BITMAPS &&
-           nested_vmx_merge_msr_bitmap(vcpu, vmcs12)) {
-               vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_nested));
+           exec_control & CPU_BASED_USE_MSR_BITMAPS) {
+               nested_vmx_merge_msr_bitmap(vcpu, vmcs12);
+               /* MSR_BITMAP will be set by following vmx_set_efer. */
        } else
                exec_control &= ~CPU_BASED_USE_MSR_BITMAPS;
 
index bd7a70b..32bf19e 100644 (file)
@@ -2744,7 +2744,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_USER_NMI:
        case KVM_CAP_REINJECT_CONTROL:
        case KVM_CAP_IRQ_INJECT_STATUS:
-       case KVM_CAP_IRQFD:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_IOEVENTFD_NO_LENGTH:
        case KVM_CAP_PIT2:
index 4a0890f..08f41ca 100644 (file)
@@ -1,6 +1,6 @@
 config LGUEST_GUEST
        bool "Lguest guest support"
-       depends on X86_32 && PARAVIRT
+       depends on X86_32 && PARAVIRT && PCI
        select TTY
        select VIRTUALIZATION
        select VIRTIO
@@ -8,7 +8,7 @@ config LGUEST_GUEST
        help
          Lguest is a tiny in-kernel hypervisor.  Selecting this will
          allow your kernel to boot under lguest.  This option will increase
-         your kernel size by about 6k.  If in doubt, say N.
+         your kernel size by about 10k.  If in doubt, say N.
 
          If you say Y here, make sure you say Y (or M) to the virtio block
          and net drivers which lguest needs.
index 6ac2738..e469598 100644 (file)
@@ -331,7 +331,7 @@ static void probe_pci_root_info(struct pci_root_info *info,
                                struct list_head *list)
 {
        int ret;
-       struct resource_entry *entry;
+       struct resource_entry *entry, *tmp;
 
        sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
        info->bridge = device;
@@ -345,8 +345,13 @@ static void probe_pci_root_info(struct pci_root_info *info,
                dev_dbg(&device->dev,
                        "no IO and memory resources present in _CRS\n");
        else
-               resource_list_for_each_entry(entry, list)
-                       entry->res->name = info->name;
+               resource_list_for_each_entry_safe(entry, tmp, list) {
+                       if ((entry->res->flags & IORESOURCE_WINDOW) == 0 ||
+                           (entry->res->flags & IORESOURCE_DISABLED))
+                               resource_list_destroy_entry(entry);
+                       else
+                               entry->res->name = info->name;
+               }
 }
 
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
index 3d2612b..2fb3847 100644 (file)
@@ -513,31 +513,6 @@ void __init pcibios_set_cache_line_size(void)
        }
 }
 
-/*
- * Some device drivers assume dev->irq won't change after calling
- * pci_disable_device(). So delay releasing of IRQ resource to driver
- * unbinding time. Otherwise it will break PM subsystem and drivers
- * like xen-pciback etc.
- */
-static int pci_irq_notifier(struct notifier_block *nb, unsigned long action,
-                           void *data)
-{
-       struct pci_dev *dev = to_pci_dev(data);
-
-       if (action != BUS_NOTIFY_UNBOUND_DRIVER)
-               return NOTIFY_DONE;
-
-       if (pcibios_disable_irq)
-               pcibios_disable_irq(dev);
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block pci_irq_nb = {
-       .notifier_call = pci_irq_notifier,
-       .priority = INT_MIN,
-};
-
 int __init pcibios_init(void)
 {
        if (!raw_pci_ops) {
@@ -550,9 +525,6 @@ int __init pcibios_init(void)
 
        if (pci_bf_sort >= pci_force_bf)
                pci_sort_breadthfirst();
-
-       bus_register_notifier(&pci_bus_type, &pci_irq_nb);
-
        return 0;
 }
 
@@ -711,6 +683,12 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return 0;
 }
 
+void pcibios_disable_device (struct pci_dev *dev)
+{
+       if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
+               pcibios_disable_irq(dev);
+}
+
 int pci_ext_cfg_avail(void)
 {
        if (raw_pci_ext_ops)
index efb8493..852aa4c 100644 (file)
@@ -234,10 +234,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 
 static void intel_mid_pci_irq_disable(struct pci_dev *dev)
 {
-       if (dev->irq_managed && dev->irq > 0) {
+       if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
+           dev->irq > 0) {
                mp_unmap_irq(dev->irq);
                dev->irq_managed = 0;
-               dev->irq = 0;
        }
 }
 
index e71b3db..5dc6ca5 100644 (file)
@@ -1256,9 +1256,22 @@ static int pirq_enable_irq(struct pci_dev *dev)
        return 0;
 }
 
+bool mp_should_keep_irq(struct device *dev)
+{
+       if (dev->power.is_prepared)
+               return true;
+#ifdef CONFIG_PM
+       if (dev->power.runtime_status == RPM_SUSPENDING)
+               return true;
+#endif
+
+       return false;
+}
+
 static void pirq_disable_irq(struct pci_dev *dev)
 {
-       if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) {
+       if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
+           dev->irq_managed && dev->irq) {
                mp_unmap_irq(dev->irq);
                dev->irq = 0;
                dev->irq_managed = 0;
index 1bbedc4..3005f0c 100644 (file)
@@ -130,7 +130,7 @@ static void intel_mid_arch_setup(void)
                intel_mid_ops = get_intel_mid_ops[__intel_mid_cpu_chip]();
        else {
                intel_mid_ops = get_intel_mid_ops[INTEL_MID_CPU_CHIP_PENWELL]();
-               pr_info("ARCH: Uknown SoC, assuming PENWELL!\n");
+               pr_info("ARCH: Unknown SoC, assuming PENWELL!\n");
        }
 
 out:
index 31776d0..d7ec4e2 100644 (file)
@@ -17,6 +17,7 @@
        .text
        .globl __kernel_sigreturn
        .type __kernel_sigreturn,@function
+       nop /* this guy is needed for .LSTARTFDEDLSI1 below (watch for HACK) */
        ALIGN
 __kernel_sigreturn:
 .LSTART_sigreturn:
index bd8b845..5240f56 100644 (file)
@@ -1070,6 +1070,23 @@ static inline void xen_write_cr8(unsigned long val)
        BUG_ON(val);
 }
 #endif
+
+static u64 xen_read_msr_safe(unsigned int msr, int *err)
+{
+       u64 val;
+
+       val = native_read_msr_safe(msr, err);
+       switch (msr) {
+       case MSR_IA32_APICBASE:
+#ifdef CONFIG_X86_X2APIC
+               if (!(cpuid_ecx(1) & (1 << (X86_FEATURE_X2APIC & 31))))
+#endif
+                       val &= ~X2APIC_ENABLE;
+               break;
+       }
+       return val;
+}
+
 static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
 {
        int ret;
@@ -1240,7 +1257,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
 
        .wbinvd = native_wbinvd,
 
-       .read_msr = native_read_msr_safe,
+       .read_msr = xen_read_msr_safe,
        .write_msr = xen_write_msr_safe,
 
        .read_tsc = native_read_tsc,
@@ -1741,6 +1758,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
 #ifdef CONFIG_X86_32
        i386_start_kernel();
 #else
+       cr4_init_shadow(); /* 32b kernel does this in i386_start_kernel() */
        x86_64_start_reservations((char *)__pa_symbol(&boot_params));
 #endif
 }
index 740ae30..b47124d 100644 (file)
@@ -91,6 +91,12 @@ EXPORT_SYMBOL_GPL(xen_p2m_size);
 unsigned long xen_max_p2m_pfn __read_mostly;
 EXPORT_SYMBOL_GPL(xen_max_p2m_pfn);
 
+#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+#define P2M_LIMIT CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+#else
+#define P2M_LIMIT 0
+#endif
+
 static DEFINE_SPINLOCK(p2m_update_lock);
 
 static unsigned long *p2m_mid_missing_mfn;
@@ -385,9 +391,11 @@ static void __init xen_rebuild_p2m_list(unsigned long *p2m)
 void __init xen_vmalloc_p2m_tree(void)
 {
        static struct vm_struct vm;
+       unsigned long p2m_limit;
 
+       p2m_limit = (phys_addr_t)P2M_LIMIT * 1024 * 1024 * 1024 / PAGE_SIZE;
        vm.flags = VM_ALLOC;
-       vm.size = ALIGN(sizeof(unsigned long) * xen_max_p2m_pfn,
+       vm.size = ALIGN(sizeof(unsigned long) * max(xen_max_p2m_pfn, p2m_limit),
                        PMD_SIZE * PMDS_PER_MID_PAGE);
        vm_area_register_early(&vm, PMD_SIZE * PMDS_PER_MID_PAGE);
        pr_notice("p2m virtual area at %p, size is %lx\n", vm.addr, vm.size);
@@ -563,7 +571,7 @@ static bool alloc_p2m(unsigned long pfn)
                if (p2m_pfn == PFN_DOWN(__pa(p2m_missing)))
                        p2m_init(p2m);
                else
-                       p2m_init_identity(p2m, pfn);
+                       p2m_init_identity(p2m, pfn & ~(P2M_PER_PAGE - 1));
 
                spin_lock_irqsave(&p2m_update_lock, flags);
 
index fc1ff3b..fd3fee8 100644 (file)
@@ -592,7 +592,7 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
        if (q->queue_flags & (1 << QUEUE_FLAG_SG_GAPS)) {
                struct bio_vec *bprev;
 
-               bprev = &rq->biotail->bi_io_vec[bio->bi_vcnt - 1];
+               bprev = &rq->biotail->bi_io_vec[rq->biotail->bi_vcnt - 1];
                if (bvec_gap_to_prev(bprev, bio->bi_io_vec[0].bv_offset))
                        return false;
        }
index d53a764..be3290c 100644 (file)
@@ -278,9 +278,11 @@ static int bt_get(struct blk_mq_alloc_data *data,
                /*
                 * We're out of tags on this hardware queue, kick any
                 * pending IO submits before going to sleep waiting for
-                * some to complete.
+                * some to complete. Note that hctx can be NULL here for
+                * reserved tag allocation.
                 */
-               blk_mq_run_hw_queue(hctx, false);
+               if (hctx)
+                       blk_mq_run_hw_queue(hctx, false);
 
                /*
                 * Retry tag allocation after running the hardware queue,
index 4f4bea2..b7b8933 100644 (file)
@@ -1938,7 +1938,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
         */
        if (percpu_ref_init(&q->mq_usage_counter, blk_mq_usage_counter_release,
                            PERCPU_REF_INIT_ATOMIC, GFP_KERNEL))
-               goto err_map;
+               goto err_mq_usage;
 
        setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q);
        blk_queue_rq_timeout(q, 30000);
@@ -1981,7 +1981,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
        blk_mq_init_cpu_queues(q, set->nr_hw_queues);
 
        if (blk_mq_init_hw_queues(q, set))
-               goto err_hw;
+               goto err_mq_usage;
 
        mutex_lock(&all_q_mutex);
        list_add_tail(&q->all_q_node, &all_q_list);
@@ -1993,7 +1993,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
 
        return q;
 
-err_hw:
+err_mq_usage:
        blk_cleanup_queue(q);
 err_hctxs:
        kfree(map);
index 6ed2cbe..12600bf 100644 (file)
@@ -585,7 +585,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                                     b->physical_block_size);
 
        t->io_min = max(t->io_min, b->io_min);
-       t->io_opt = lcm(t->io_opt, b->io_opt);
+       t->io_opt = lcm_not_zero(t->io_opt, b->io_opt);
 
        t->cluster &= b->cluster;
        t->discard_zeroes_data &= b->discard_zeroes_data;
@@ -616,7 +616,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                    b->raid_partial_stripes_expensive);
 
        /* Find lowest common alignment_offset */
-       t->alignment_offset = lcm(t->alignment_offset, alignment)
+       t->alignment_offset = lcm_not_zero(t->alignment_offset, alignment)
                % max(t->physical_block_size, t->io_min);
 
        /* Verify that new alignment_offset is on a logical block boundary */
@@ -643,7 +643,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                                                      b->max_discard_sectors);
                t->discard_granularity = max(t->discard_granularity,
                                             b->discard_granularity);
-               t->discard_alignment = lcm(t->discard_alignment, alignment) %
+               t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) %
                        t->discard_granularity;
        }
 
index 657964e..37fb190 100644 (file)
@@ -65,6 +65,7 @@ struct lpss_private_data;
 
 struct lpss_device_desc {
        unsigned int flags;
+       const char *clk_con_id;
        unsigned int prv_offset;
        size_t prv_size_override;
        void (*setup)(struct lpss_private_data *pdata);
@@ -140,6 +141,7 @@ static struct lpss_device_desc lpt_i2c_dev_desc = {
 
 static struct lpss_device_desc lpt_uart_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
+       .clk_con_id = "baudclk",
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
@@ -156,6 +158,7 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
 
 static struct lpss_device_desc byt_uart_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+       .clk_con_id = "baudclk",
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
@@ -313,7 +316,7 @@ out:
                return PTR_ERR(clk);
 
        pdata->clk = clk;
-       clk_register_clkdev(clk, NULL, devname);
+       clk_register_clkdev(clk, dev_desc->clk_con_id, devname);
        return 0;
 }
 
index e7f718d..b1def41 100644 (file)
@@ -485,6 +485,14 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        if (!pin || !dev->irq_managed || dev->irq <= 0)
                return;
 
+       /* Keep IOAPIC pin configuration when suspending */
+       if (dev->dev.power.is_prepared)
+               return;
+#ifdef CONFIG_PM
+       if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+               return;
+#endif
+
        entry = acpi_pci_irq_lookup(dev, pin);
        if (!entry)
                return;
@@ -505,6 +513,5 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        if (gsi >= 0) {
                acpi_unregister_gsi(gsi);
                dev->irq_managed = 0;
-               dev->irq = 0;
        }
 }
index c723668..5589a6e 100644 (file)
@@ -42,8 +42,10 @@ static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
         * CHECKME: len might be required to check versus a minimum
         * length as well. 1 for io is fine, but for memory it does
         * not make any sense at all.
+        * Note: some BIOSes report incorrect length for ACPI address space
+        * descriptor, so remove check of 'reslen == len' to avoid regression.
         */
-       if (len && reslen && reslen == len && start <= end)
+       if (len && reslen && start <= end)
                return true;
 
        pr_debug("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n",
index debd309..26eb70c 100644 (file)
@@ -2110,7 +2110,8 @@ static int __init intel_opregion_present(void)
 
 int acpi_video_register(void)
 {
-       int result = 0;
+       int ret;
+
        if (register_count) {
                /*
                 * if the function of acpi_video_register is already called,
@@ -2122,9 +2123,9 @@ int acpi_video_register(void)
        mutex_init(&video_list_lock);
        INIT_LIST_HEAD(&video_bus_head);
 
-       result = acpi_bus_register_driver(&acpi_video_bus);
-       if (result < 0)
-               return -ENODEV;
+       ret = acpi_bus_register_driver(&acpi_video_bus);
+       if (ret)
+               return ret;
 
        /*
         * When the acpi_video_bus is loaded successfully, increase
@@ -2176,6 +2177,17 @@ EXPORT_SYMBOL(acpi_video_unregister_backlight);
 
 static int __init acpi_video_init(void)
 {
+       /*
+        * Let the module load even if ACPI is disabled (e.g. due to
+        * a broken BIOS) so that i915.ko can still be loaded on such
+        * old systems without an AcpiOpRegion.
+        *
+        * acpi_video_register() will report -ENODEV later as well due
+        * to acpi_disabled when i915.ko tries to register itself afterwards.
+        */
+       if (acpi_disabled)
+               return 0;
+
        dmi_check_system(video_dmi_table);
 
        if (intel_opregion_present())
index 33b09b6..6607f3c 100644 (file)
@@ -551,7 +551,6 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
 {
        void *page_addr;
        unsigned long user_page_addr;
-       struct vm_struct tmp_area;
        struct page **page;
        struct mm_struct *mm;
 
@@ -600,10 +599,11 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
                                proc->pid, page_addr);
                        goto err_alloc_page_failed;
                }
-               tmp_area.addr = page_addr;
-               tmp_area.size = PAGE_SIZE + PAGE_SIZE /* guard page? */;
-               ret = map_vm_area(&tmp_area, PAGE_KERNEL, page);
-               if (ret) {
+               ret = map_kernel_range_noflush((unsigned long)page_addr,
+                                       PAGE_SIZE, PAGE_KERNEL, page);
+               flush_cache_vmap((unsigned long)page_addr,
+                               (unsigned long)page_addr + PAGE_SIZE);
+               if (ret != 1) {
                        pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n",
                               proc->pid, page_addr);
                        goto err_map_kernel_failed;
index 4c35f08..23dac3b 100644 (file)
@@ -4204,9 +4204,18 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
        /* devices that don't properly handle queued TRIM commands */
-       { "Micron_M[56]*",              NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+       { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*M500*",           NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Micron_M5[15]0*",            "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*M550*",           "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*MX100*",          "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Samsung SSD 850 PRO*",       NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
-       { "Crucial_CT*SSD*",            NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
 
        /*
         * As defined, the DRAT (Deterministic Read After Trim) and RZAT
@@ -4226,6 +4235,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         */
        { "INTEL*SSDSC2MH*",            NULL,   0, },
 
+       { "Micron*",                    NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial*",                   NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "INTEL*SSD*",                 NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "SSD*INTEL*",                 NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "Samsung*SSD*",               NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
@@ -4737,7 +4748,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
                return NULL;
 
        /* libsas case */
-       if (!ap->scsi_host) {
+       if (ap->flags & ATA_FLAG_SAS_HOST) {
                tag = ata_sas_allocate_tag(ap);
                if (tag < 0)
                        return NULL;
@@ -4776,7 +4787,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
        tag = qc->tag;
        if (likely(ata_tag_valid(tag))) {
                qc->tag = ATA_TAG_POISON;
-               if (!ap->scsi_host)
+               if (ap->flags & ATA_FLAG_SAS_HOST)
                        ata_sas_free_tag(tag, ap);
        }
 }
index f9054cd..5389579 100644 (file)
@@ -869,6 +869,8 @@ try_offline_again:
         */
        ata_msleep(ap, 1);
 
+       sata_set_spd(link);
+
        /*
         * Now, bring the host controller online again, this can take time
         * as PHY reset and communication establishment, 1st D2H FIS and
index ba4abbe..45937f8 100644 (file)
@@ -2242,7 +2242,7 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
 }
 
 static int pm_genpd_summary_one(struct seq_file *s,
-               struct generic_pm_domain *gpd)
+                               struct generic_pm_domain *genpd)
 {
        static const char * const status_lookup[] = {
                [GPD_STATE_ACTIVE] = "on",
@@ -2256,26 +2256,26 @@ static int pm_genpd_summary_one(struct seq_file *s,
        struct gpd_link *link;
        int ret;
 
-       ret = mutex_lock_interruptible(&gpd->lock);
+       ret = mutex_lock_interruptible(&genpd->lock);
        if (ret)
                return -ERESTARTSYS;
 
-       if (WARN_ON(gpd->status >= ARRAY_SIZE(status_lookup)))
+       if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
                goto exit;
-       seq_printf(s, "%-30s  %-15s  ", gpd->name, status_lookup[gpd->status]);
+       seq_printf(s, "%-30s  %-15s  ", genpd->name, status_lookup[genpd->status]);
 
        /*
         * Modifications on the list require holding locks on both
         * master and slave, so we are safe.
-        * Also gpd->name is immutable.
+        * Also genpd->name is immutable.
         */
-       list_for_each_entry(link, &gpd->master_links, master_node) {
+       list_for_each_entry(link, &genpd->master_links, master_node) {
                seq_printf(s, "%s", link->slave->name);
-               if (!list_is_last(&link->master_node, &gpd->master_links))
+               if (!list_is_last(&link->master_node, &genpd->master_links))
                        seq_puts(s, ", ");
        }
 
-       list_for_each_entry(pm_data, &gpd->dev_list, list_node) {
+       list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
                kobj_path = kobject_get_path(&pm_data->dev->kobj, GFP_KERNEL);
                if (kobj_path == NULL)
                        continue;
@@ -2287,14 +2287,14 @@ static int pm_genpd_summary_one(struct seq_file *s,
 
        seq_puts(s, "\n");
 exit:
-       mutex_unlock(&gpd->lock);
+       mutex_unlock(&genpd->lock);
 
        return 0;
 }
 
 static int pm_genpd_summary_show(struct seq_file *s, void *data)
 {
-       struct generic_pm_domain *gpd;
+       struct generic_pm_domain *genpd;
        int ret = 0;
 
        seq_puts(s, "    domain                      status         slaves\n");
@@ -2305,8 +2305,8 @@ static int pm_genpd_summary_show(struct seq_file *s, void *data)
        if (ret)
                return -ERESTARTSYS;
 
-       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
-               ret = pm_genpd_summary_one(s, gpd);
+       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
+               ret = pm_genpd_summary_one(s, genpd);
                if (ret)
                        break;
        }
index c2744b3..aab7158 100644 (file)
@@ -730,6 +730,7 @@ void pm_system_wakeup(void)
        pm_abort_suspend = true;
        freeze_wake();
 }
+EXPORT_SYMBOL_GPL(pm_system_wakeup);
 
 void pm_wakeup_clear(void)
 {
index beb8b27..a13587b 100644 (file)
@@ -243,4 +243,12 @@ extern struct regcache_ops regcache_rbtree_ops;
 extern struct regcache_ops regcache_lzo_ops;
 extern struct regcache_ops regcache_flat_ops;
 
+static inline const char *regmap_name(const struct regmap *map)
+{
+       if (map->dev)
+               return dev_name(map->dev);
+
+       return map->name;
+}
+
 #endif
index d453a2c..81751a4 100644 (file)
@@ -307,7 +307,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
        if (pos == 0) {
                memmove(blk + offset * map->cache_word_size,
                        blk, rbnode->blklen * map->cache_word_size);
-               bitmap_shift_right(present, present, offset, blklen);
+               bitmap_shift_left(present, present, offset, blklen);
        }
 
        /* update the rbnode block, its size and the base register */
index f373c35..87db989 100644 (file)
@@ -218,7 +218,7 @@ int regcache_read(struct regmap *map,
                ret = map->cache_ops->read(map, reg, value);
 
                if (ret == 0)
-                       trace_regmap_reg_read_cache(map->dev, reg, *value);
+                       trace_regmap_reg_read_cache(map, reg, *value);
 
                return ret;
        }
@@ -311,7 +311,7 @@ int regcache_sync(struct regmap *map)
        dev_dbg(map->dev, "Syncing %s cache\n",
                map->cache_ops->name);
        name = map->cache_ops->name;
-       trace_regcache_sync(map->dev, name, "start");
+       trace_regcache_sync(map, name, "start");
 
        if (!map->cache_dirty)
                goto out;
@@ -346,7 +346,7 @@ out:
 
        regmap_async_complete(map);
 
-       trace_regcache_sync(map->dev, name, "stop");
+       trace_regcache_sync(map, name, "stop");
 
        return ret;
 }
@@ -381,7 +381,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
        name = map->cache_ops->name;
        dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
 
-       trace_regcache_sync(map->dev, name, "start region");
+       trace_regcache_sync(map, name, "start region");
 
        if (!map->cache_dirty)
                goto out;
@@ -401,7 +401,7 @@ out:
 
        regmap_async_complete(map);
 
-       trace_regcache_sync(map->dev, name, "stop region");
+       trace_regcache_sync(map, name, "stop region");
 
        return ret;
 }
@@ -428,7 +428,7 @@ int regcache_drop_region(struct regmap *map, unsigned int min,
 
        map->lock(map->lock_arg);
 
-       trace_regcache_drop_region(map->dev, min, max);
+       trace_regcache_drop_region(map, min, max);
 
        ret = map->cache_ops->drop(map, min, max);
 
@@ -455,7 +455,7 @@ void regcache_cache_only(struct regmap *map, bool enable)
        map->lock(map->lock_arg);
        WARN_ON(map->cache_bypass && enable);
        map->cache_only = enable;
-       trace_regmap_cache_only(map->dev, enable);
+       trace_regmap_cache_only(map, enable);
        map->unlock(map->lock_arg);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -493,7 +493,7 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
        map->lock(map->lock_arg);
        WARN_ON(map->cache_only && enable);
        map->cache_bypass = enable;
-       trace_regmap_cache_bypass(map->dev, enable);
+       trace_regmap_cache_bypass(map, enable);
        map->unlock(map->lock_arg);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@ -608,7 +608,8 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
        for (i = start; i < end; i++) {
                regtmp = block_base + (i * map->reg_stride);
 
-               if (!regcache_reg_present(cache_present, i))
+               if (!regcache_reg_present(cache_present, i) ||
+                   !regmap_writeable(map, regtmp))
                        continue;
 
                val = regcache_get_val(map, block, i);
@@ -677,7 +678,8 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
        for (i = start; i < end; i++) {
                regtmp = block_base + (i * map->reg_stride);
 
-               if (!regcache_reg_present(cache_present, i)) {
+               if (!regcache_reg_present(cache_present, i) ||
+                   !regmap_writeable(map, regtmp)) {
                        ret = regcache_sync_block_raw_flush(map, &data,
                                                            base, regtmp);
                        if (ret != 0)
index 6299a50..a6c3f75 100644 (file)
@@ -499,7 +499,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                goto err_alloc;
        }
 
-       ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
+       ret = request_threaded_irq(irq, NULL, regmap_irq_thread,
+                                  irq_flags | IRQF_ONESHOT,
                                   chip->name, d);
        if (ret != 0) {
                dev_err(map->dev, "Failed to request IRQ %d for %s: %d\n",
index f99b098..dbfe6a6 100644 (file)
@@ -1281,7 +1281,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
        if (map->async && map->bus->async_write) {
                struct regmap_async *async;
 
-               trace_regmap_async_write_start(map->dev, reg, val_len);
+               trace_regmap_async_write_start(map, reg, val_len);
 
                spin_lock_irqsave(&map->async_lock, flags);
                async = list_first_entry_or_null(&map->async_free,
@@ -1339,8 +1339,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                return ret;
        }
 
-       trace_regmap_hw_write_start(map->dev, reg,
-                                   val_len / map->format.val_bytes);
+       trace_regmap_hw_write_start(map, reg, val_len / map->format.val_bytes);
 
        /* If we're doing a single register write we can probably just
         * send the work_buf directly, otherwise try to do a gather
@@ -1372,8 +1371,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                kfree(buf);
        }
 
-       trace_regmap_hw_write_done(map->dev, reg,
-                                  val_len / map->format.val_bytes);
+       trace_regmap_hw_write_done(map, reg, val_len / map->format.val_bytes);
 
        return ret;
 }
@@ -1407,12 +1405,12 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
 
        map->format.format_write(map, reg, val);
 
-       trace_regmap_hw_write_start(map->dev, reg, 1);
+       trace_regmap_hw_write_start(map, reg, 1);
 
        ret = map->bus->write(map->bus_context, map->work_buf,
                              map->format.buf_size);
 
-       trace_regmap_hw_write_done(map->dev, reg, 1);
+       trace_regmap_hw_write_done(map, reg, 1);
 
        return ret;
 }
@@ -1470,7 +1468,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
                dev_info(map->dev, "%x <= %x\n", reg, val);
 #endif
 
-       trace_regmap_reg_write(map->dev, reg, val);
+       trace_regmap_reg_write(map, reg, val);
 
        return map->reg_write(context, reg, val);
 }
@@ -1773,7 +1771,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
        for (i = 0; i < num_regs; i++) {
                int reg = regs[i].reg;
                int val = regs[i].def;
-               trace_regmap_hw_write_start(map->dev, reg, 1);
+               trace_regmap_hw_write_start(map, reg, 1);
                map->format.format_reg(u8, reg, map->reg_shift);
                u8 += reg_bytes + pad_bytes;
                map->format.format_val(u8, val, 0);
@@ -1788,7 +1786,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
 
        for (i = 0; i < num_regs; i++) {
                int reg = regs[i].reg;
-               trace_regmap_hw_write_done(map->dev, reg, 1);
+               trace_regmap_hw_write_done(map, reg, 1);
        }
        return ret;
 }
@@ -2059,15 +2057,13 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
         */
        u8[0] |= map->read_flag_mask;
 
-       trace_regmap_hw_read_start(map->dev, reg,
-                                  val_len / map->format.val_bytes);
+       trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes);
 
        ret = map->bus->read(map->bus_context, map->work_buf,
                             map->format.reg_bytes + map->format.pad_bytes,
                             val, val_len);
 
-       trace_regmap_hw_read_done(map->dev, reg,
-                                 val_len / map->format.val_bytes);
+       trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes);
 
        return ret;
 }
@@ -2123,7 +2119,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
                        dev_info(map->dev, "%x => %x\n", reg, *val);
 #endif
 
-               trace_regmap_reg_read(map->dev, reg, *val);
+               trace_regmap_reg_read(map, reg, *val);
 
                if (!map->cache_bypass)
                        regcache_write(map, reg, *val);
@@ -2480,7 +2476,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
        struct regmap *map = async->map;
        bool wake;
 
-       trace_regmap_async_io_complete(map->dev);
+       trace_regmap_async_io_complete(map);
 
        spin_lock(&map->async_lock);
        list_move(&async->list, &map->async_free);
@@ -2525,7 +2521,7 @@ int regmap_async_complete(struct regmap *map)
        if (!map->bus || !map->bus->async_write)
                return 0;
 
-       trace_regmap_async_complete_start(map->dev);
+       trace_regmap_async_complete_start(map);
 
        wait_event(map->async_waitq, regmap_async_is_done(map));
 
@@ -2534,7 +2530,7 @@ int regmap_async_complete(struct regmap *map)
        map->async_ret = 0;
        spin_unlock_irqrestore(&map->async_lock, flags);
 
-       trace_regmap_async_complete_done(map->dev);
+       trace_regmap_async_complete_done(map);
 
        return ret;
 }
index 4bc2a5c..a98c41f 100644 (file)
@@ -803,10 +803,6 @@ static int __init nbd_init(void)
                return -EINVAL;
        }
 
-       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
-       if (!nbd_dev)
-               return -ENOMEM;
-
        part_shift = 0;
        if (max_part > 0) {
                part_shift = fls(max_part);
@@ -828,6 +824,10 @@ static int __init nbd_init(void)
        if (nbds_max > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
+       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
+       if (!nbd_dev)
+               return -ENOMEM;
+
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = alloc_disk(1 << part_shift);
                if (!disk)
index b64bccb..e23be20 100644 (file)
@@ -482,6 +482,7 @@ static int nvme_error_status(u16 status)
        }
 }
 
+#ifdef CONFIG_BLK_DEV_INTEGRITY
 static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
 {
        if (be32_to_cpu(pi->ref_tag) == v)
@@ -538,6 +539,58 @@ static void nvme_dif_remap(struct request *req,
        kunmap_atomic(pmap);
 }
 
+static int nvme_noop_verify(struct blk_integrity_iter *iter)
+{
+       return 0;
+}
+
+static int nvme_noop_generate(struct blk_integrity_iter *iter)
+{
+       return 0;
+}
+
+struct blk_integrity nvme_meta_noop = {
+       .name                   = "NVME_META_NOOP",
+       .generate_fn            = nvme_noop_generate,
+       .verify_fn              = nvme_noop_verify,
+};
+
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+       struct blk_integrity integrity;
+
+       switch (ns->pi_type) {
+       case NVME_NS_DPS_PI_TYPE3:
+               integrity = t10_pi_type3_crc;
+               break;
+       case NVME_NS_DPS_PI_TYPE1:
+       case NVME_NS_DPS_PI_TYPE2:
+               integrity = t10_pi_type1_crc;
+               break;
+       default:
+               integrity = nvme_meta_noop;
+               break;
+       }
+       integrity.tuple_size = ns->ms;
+       blk_integrity_register(ns->disk, &integrity);
+       blk_queue_max_integrity_segments(ns->queue, 1);
+}
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+static void nvme_dif_remap(struct request *req,
+                       void (*dif_swap)(u32 p, u32 v, struct t10_pi_tuple *pi))
+{
+}
+static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+}
+static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+}
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+}
+#endif
+
 static void req_completion(struct nvme_queue *nvmeq, void *ctx,
                                                struct nvme_completion *cqe)
 {
@@ -1959,43 +2012,6 @@ static void nvme_config_discard(struct nvme_ns *ns)
        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
 }
 
-static int nvme_noop_verify(struct blk_integrity_iter *iter)
-{
-       return 0;
-}
-
-static int nvme_noop_generate(struct blk_integrity_iter *iter)
-{
-       return 0;
-}
-
-struct blk_integrity nvme_meta_noop = {
-       .name                   = "NVME_META_NOOP",
-       .generate_fn            = nvme_noop_generate,
-       .verify_fn              = nvme_noop_verify,
-};
-
-static void nvme_init_integrity(struct nvme_ns *ns)
-{
-       struct blk_integrity integrity;
-
-       switch (ns->pi_type) {
-       case NVME_NS_DPS_PI_TYPE3:
-               integrity = t10_pi_type3_crc;
-               break;
-       case NVME_NS_DPS_PI_TYPE1:
-       case NVME_NS_DPS_PI_TYPE2:
-               integrity = t10_pi_type1_crc;
-               break;
-       default:
-               integrity = nvme_meta_noop;
-               break;
-       }
-       integrity.tuple_size = ns->ms;
-       blk_integrity_register(ns->disk, &integrity);
-       blk_queue_max_integrity_segments(ns->queue, 1);
-}
-
 static int nvme_revalidate_disk(struct gendisk *disk)
 {
        struct nvme_ns *ns = disk->private_data;
@@ -2036,7 +2052,8 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        pi_type = ns->ms == sizeof(struct t10_pi_tuple) ?
                                        id->dps & NVME_NS_DPS_PI_MASK : 0;
 
-       if (disk->integrity && (ns->pi_type != pi_type || ns->ms != old_ms ||
+       if (blk_get_integrity(disk) && (ns->pi_type != pi_type ||
+                               ns->ms != old_ms ||
                                bs != queue_logical_block_size(disk->queue) ||
                                (ns->ms && id->flbas & NVME_NS_FLBAS_META_EXT)))
                blk_integrity_unregister(disk);
@@ -2044,11 +2061,11 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        ns->pi_type = pi_type;
        blk_queue_logical_block_size(ns->queue, bs);
 
-       if (ns->ms && !disk->integrity && (disk->flags & GENHD_FL_UP) &&
+       if (ns->ms && !blk_get_integrity(disk) && (disk->flags & GENHD_FL_UP) &&
                                !(id->flbas & NVME_NS_FLBAS_META_EXT))
                nvme_init_integrity(ns);
 
-       if (id->ncap == 0 || (ns->ms && !disk->integrity))
+       if (id->ncap == 0 || (ns->ms && !blk_get_integrity(disk)))
                set_capacity(disk, 0);
        else
                set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
@@ -2652,7 +2669,7 @@ static void nvme_dev_remove(struct nvme_dev *dev)
 
        list_for_each_entry(ns, &dev->namespaces, list) {
                if (ns->disk->flags & GENHD_FL_UP) {
-                       if (ns->disk->integrity)
+                       if (blk_get_integrity(ns->disk))
                                blk_integrity_unregister(ns->disk);
                        del_gendisk(ns->disk);
                }
@@ -2986,6 +3003,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        get_device(dev->device);
 
+       INIT_LIST_HEAD(&dev->node);
        INIT_WORK(&dev->probe_work, nvme_async_probe);
        schedule_work(&dev->probe_work);
        return 0;
index 8e233ed..871bd35 100644 (file)
@@ -528,7 +528,7 @@ out_cleanup:
 static inline void update_used_max(struct zram *zram,
                                        const unsigned long pages)
 {
-       int old_max, cur_max;
+       unsigned long old_max, cur_max;
 
        old_max = atomic_long_read(&zram->stats.max_used_pages);
 
index b876888..8bfc4c2 100644 (file)
@@ -272,6 +272,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
 
        /* Intel Bluetooth devices */
+       { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
        { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
        { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
        { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW },
index 1d278cc..e096e9c 100644 (file)
@@ -140,24 +140,24 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
 {
        int rc;
 
-       rc = device_add(&chip->dev);
+       rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
        if (rc) {
                dev_err(&chip->dev,
-                       "unable to device_register() %s, major %d, minor %d, err=%d\n",
+                       "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
                        chip->devname, MAJOR(chip->dev.devt),
                        MINOR(chip->dev.devt), rc);
 
+               device_unregister(&chip->dev);
                return rc;
        }
 
-       rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
+       rc = device_add(&chip->dev);
        if (rc) {
                dev_err(&chip->dev,
-                       "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+                       "unable to device_register() %s, major %d, minor %d, err=%d\n",
                        chip->devname, MAJOR(chip->dev.devt),
                        MINOR(chip->dev.devt), rc);
 
-               device_unregister(&chip->dev);
                return rc;
        }
 
@@ -174,27 +174,17 @@ static void tpm_dev_del_device(struct tpm_chip *chip)
  * tpm_chip_register() - create a character device for the TPM chip
  * @chip: TPM chip to use.
  *
- * Creates a character device for the TPM chip and adds sysfs interfaces for
- * the device, PPI and TCPA. As the last step this function adds the
- * chip to the list of TPM chips available for use.
+ * Creates a character device for the TPM chip and adds sysfs attributes for
+ * the device. As the last step this function adds the chip to the list of TPM
+ * chips available for in-kernel use.
  *
- * NOTE: This function should be only called after the chip initialization
- * is complete.
- *
- * Called from tpm_<specific>.c probe function only for devices
- * the driver has determined it should claim.  Prior to calling
- * this function the specific probe function has called pci_enable_device
- * upon errant exit from this function specific probe function should call
- * pci_disable_device
+ * This function should be only called after the chip initialization is
+ * complete.
  */
 int tpm_chip_register(struct tpm_chip *chip)
 {
        int rc;
 
-       rc = tpm_dev_add_device(chip);
-       if (rc)
-               return rc;
-
        /* Populate sysfs for TPM1 devices. */
        if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
                rc = tpm_sysfs_add_device(chip);
@@ -208,6 +198,10 @@ int tpm_chip_register(struct tpm_chip *chip)
                chip->bios_dir = tpm_bios_log_setup(chip->devname);
        }
 
+       rc = tpm_dev_add_device(chip);
+       if (rc)
+               return rc;
+
        /* Make the chip available. */
        spin_lock(&driver_lock);
        list_add_rcu(&chip->list, &tpm_chip_list);
index b1e53e3..42ffa5e 100644 (file)
@@ -124,7 +124,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
 {
        struct ibmvtpm_dev *ibmvtpm;
        struct ibmvtpm_crq crq;
-       u64 *word = (u64 *) &crq;
+       __be64 *word = (__be64 *)&crq;
        int rc;
 
        ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
@@ -145,11 +145,11 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
        memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
        crq.valid = (u8)IBMVTPM_VALID_CMD;
        crq.msg = (u8)VTPM_TPM_COMMAND;
-       crq.len = (u16)count;
-       crq.data = ibmvtpm->rtce_dma_handle;
+       crq.len = cpu_to_be16(count);
+       crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
 
-       rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]),
-                             cpu_to_be64(word[1]));
+       rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]),
+                             be64_to_cpu(word[1]));
        if (rc != H_SUCCESS) {
                dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
                rc = 0;
index f595f14..6af9289 100644 (file)
@@ -22,9 +22,9 @@
 struct ibmvtpm_crq {
        u8 valid;
        u8 msg;
-       u16 len;
-       u32 data;
-       u64 reserved;
+       __be16 len;
+       __be32 data;
+       __be64 reserved;
 } __attribute__((packed, aligned(8)));
 
 struct ibmvtpm_crq_queue {
index fae2dbb..72d7028 100644 (file)
@@ -142,6 +142,7 @@ struct ports_device {
         * notification
         */
        struct work_struct control_work;
+       struct work_struct config_work;
 
        struct list_head ports;
 
@@ -1837,10 +1838,21 @@ static void config_intr(struct virtio_device *vdev)
 
        portdev = vdev->priv;
 
+       if (!use_multiport(portdev))
+               schedule_work(&portdev->config_work);
+}
+
+static void config_work_handler(struct work_struct *work)
+{
+       struct ports_device *portdev;
+
+       portdev = container_of(work, struct ports_device, control_work);
        if (!use_multiport(portdev)) {
+               struct virtio_device *vdev;
                struct port *port;
                u16 rows, cols;
 
+               vdev = portdev->vdev;
                virtio_cread(vdev, struct virtio_console_config, cols, &cols);
                virtio_cread(vdev, struct virtio_console_config, rows, &rows);
 
@@ -2040,12 +2052,14 @@ static int virtcons_probe(struct virtio_device *vdev)
 
        virtio_device_ready(portdev->vdev);
 
+       INIT_WORK(&portdev->config_work, &config_work_handler);
+       INIT_WORK(&portdev->control_work, &control_work_handler);
+
        if (multiport) {
                unsigned int nr_added_bufs;
 
                spin_lock_init(&portdev->c_ivq_lock);
                spin_lock_init(&portdev->c_ovq_lock);
-               INIT_WORK(&portdev->control_work, &control_work_handler);
 
                nr_added_bufs = fill_queue(portdev->c_ivq,
                                           &portdev->c_ivq_lock);
@@ -2113,6 +2127,8 @@ static void virtcons_remove(struct virtio_device *vdev)
        /* Finish up work that's lined up */
        if (use_multiport(portdev))
                cancel_work_sync(&portdev->control_work);
+       else
+               cancel_work_sync(&portdev->config_work);
 
        list_for_each_entry_safe(port, port2, &portdev->ports, list)
                unplug_port(port);
@@ -2164,6 +2180,7 @@ static int virtcons_freeze(struct virtio_device *vdev)
 
        virtqueue_disable_cb(portdev->c_ivq);
        cancel_work_sync(&portdev->control_work);
+       cancel_work_sync(&portdev->config_work);
        /*
         * Once more: if control_work_handler() was running, it would
         * enable the cb as the last step.
index f07c815..3f27d21 100644 (file)
@@ -89,12 +89,29 @@ static int pmc_irq_set_type(struct irq_data *d, unsigned type)
        return 0;
 }
 
+static void pmc_irq_suspend(struct irq_data *d)
+{
+       struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
+
+       pmc->imr = pmc_read(pmc, AT91_PMC_IMR);
+       pmc_write(pmc, AT91_PMC_IDR, pmc->imr);
+}
+
+static void pmc_irq_resume(struct irq_data *d)
+{
+       struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
+
+       pmc_write(pmc, AT91_PMC_IER, pmc->imr);
+}
+
 static struct irq_chip pmc_irq = {
        .name = "PMC",
        .irq_disable = pmc_irq_mask,
        .irq_mask = pmc_irq_mask,
        .irq_unmask = pmc_irq_unmask,
        .irq_set_type = pmc_irq_set_type,
+       .irq_suspend = pmc_irq_suspend,
+       .irq_resume = pmc_irq_resume,
 };
 
 static struct lock_class_key pmc_lock_class;
@@ -224,7 +241,8 @@ static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
                goto out_free_pmc;
 
        pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
-       if (request_irq(pmc->virq, pmc_irq_handler, IRQF_SHARED, "pmc", pmc))
+       if (request_irq(pmc->virq, pmc_irq_handler,
+                       IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc))
                goto out_remove_irqdomain;
 
        return pmc;
index 52d2041..69abb08 100644 (file)
@@ -33,6 +33,7 @@ struct at91_pmc {
        spinlock_t lock;
        const struct at91_pmc_caps *caps;
        struct irq_domain *irqdomain;
+       u32 imr;
 };
 
 static inline void pmc_lock(struct at91_pmc *pmc)
index db7f8bc..25006a8 100644 (file)
@@ -144,12 +144,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
                                   divider->flags);
 }
 
-/*
- * The reverse of DIV_ROUND_UP: The maximum number which
- * divided by m is r
- */
-#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
-
 static bool _is_valid_table_div(const struct clk_div_table *table,
                                                         unsigned int div)
 {
@@ -225,19 +219,24 @@ static int _div_round_closest(const struct clk_div_table *table,
                              unsigned long parent_rate, unsigned long rate,
                              unsigned long flags)
 {
-       int up, down, div;
+       int up, down;
+       unsigned long up_rate, down_rate;
 
-       up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       up = DIV_ROUND_UP(parent_rate, rate);
+       down = parent_rate / rate;
 
        if (flags & CLK_DIVIDER_POWER_OF_TWO) {
-               up = __roundup_pow_of_two(div);
-               down = __rounddown_pow_of_two(div);
+               up = __roundup_pow_of_two(up);
+               down = __rounddown_pow_of_two(down);
        } else if (table) {
-               up = _round_up_table(table, div);
-               down = _round_down_table(table, div);
+               up = _round_up_table(table, up);
+               down = _round_down_table(table, down);
        }
 
-       return (up - div) <= (div - down) ? up : down;
+       up_rate = DIV_ROUND_UP(parent_rate, up);
+       down_rate = DIV_ROUND_UP(parent_rate, down);
+
+       return (rate - up_rate) <= (down_rate - rate) ? up : down;
 }
 
 static int _div_round(const struct clk_div_table *table,
@@ -313,7 +312,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
                        return i;
                }
                parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
-                               MULT_ROUND_UP(rate, i));
+                                              rate * i);
                now = DIV_ROUND_UP(parent_rate, i);
                if (_is_best_div(rate, now, best, flags)) {
                        bestdiv = i;
@@ -353,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
                bestdiv = readl(divider->reg) >> divider->shift;
                bestdiv &= div_mask(divider->width);
                bestdiv = _get_div(divider->table, bestdiv, divider->flags);
-               return bestdiv;
+               return DIV_ROUND_UP(*prate, bestdiv);
        }
 
        return divider_round_rate(hw, rate, prate, divider->table,
index eb01529..237f23f 100644 (file)
@@ -1350,7 +1350,6 @@ static unsigned long clk_core_get_rate(struct clk_core *clk)
 
        return rate;
 }
-EXPORT_SYMBOL_GPL(clk_core_get_rate);
 
 /**
  * clk_get_rate - return the rate of clk
@@ -2170,6 +2169,32 @@ int clk_get_phase(struct clk *clk)
        return clk_core_get_phase(clk->core);
 }
 
+/**
+ * clk_is_match - check if two clk's point to the same hardware clock
+ * @p: clk compared against q
+ * @q: clk compared against p
+ *
+ * Returns true if the two struct clk pointers both point to the same hardware
+ * clock node. Put differently, returns true if struct clk *p and struct clk *q
+ * share the same struct clk_core object.
+ *
+ * Returns false otherwise. Note that two NULL clks are treated as matching.
+ */
+bool clk_is_match(const struct clk *p, const struct clk *q)
+{
+       /* trivial case: identical struct clk's or both NULL */
+       if (p == q)
+               return true;
+
+       /* true if clk->core pointers match. Avoid derefing garbage */
+       if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
+               if (p->core == q->core)
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(clk_is_match);
+
 /**
  * __clk_init - initialize the data structures in a struct clk
  * @dev:       device initializing this clk, placeholder for now
index b0b562b..e60feff 100644 (file)
@@ -48,6 +48,17 @@ static struct clk_pll pll3 = {
        },
 };
 
+static struct clk_regmap pll4_vote = {
+       .enable_reg = 0x34c0,
+       .enable_mask = BIT(4),
+       .hw.init = &(struct clk_init_data){
+               .name = "pll4_vote",
+               .parent_names = (const char *[]){ "pll4" },
+               .num_parents = 1,
+               .ops = &clk_pll_vote_ops,
+       },
+};
+
 static struct clk_pll pll8 = {
        .l_reg = 0x3144,
        .m_reg = 0x3148,
@@ -3023,6 +3034,7 @@ static struct clk_branch rpm_msg_ram_h_clk = {
 
 static struct clk_regmap *gcc_msm8960_clks[] = {
        [PLL3] = &pll3.clkr,
+       [PLL4_VOTE] = &pll4_vote,
        [PLL8] = &pll8.clkr,
        [PLL8_VOTE] = &pll8_vote,
        [PLL14] = &pll14.clkr,
@@ -3247,6 +3259,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
 
 static struct clk_regmap *gcc_apq8064_clks[] = {
        [PLL3] = &pll3.clkr,
+       [PLL4_VOTE] = &pll4_vote,
        [PLL8] = &pll8.clkr,
        [PLL8_VOTE] = &pll8_vote,
        [PLL14] = &pll14.clkr,
index 121ffde..c9ff27b 100644 (file)
@@ -462,7 +462,6 @@ static struct platform_driver lcc_ipq806x_driver = {
        .remove         = lcc_ipq806x_remove,
        .driver         = {
                .name   = "lcc-ipq806x",
-               .owner  = THIS_MODULE,
                .of_match_table = lcc_ipq806x_match_table,
        },
 };
index a75a408..e2c8632 100644 (file)
@@ -417,8 +417,8 @@ static struct clk_rcg slimbus_src = {
                .mnctr_en_bit = 8,
                .mnctr_reset_bit = 7,
                .mnctr_mode_shift = 5,
-               .n_val_shift = 16,
-               .m_val_shift = 16,
+               .n_val_shift = 24,
+               .m_val_shift = 8,
                .width = 8,
        },
        .p = {
@@ -547,7 +547,7 @@ static int lcc_msm8960_probe(struct platform_device *pdev)
                return PTR_ERR(regmap);
 
        /* Use the correct frequency plan depending on speed of PLL4 */
-       val = regmap_read(regmap, 0x4, &val);
+       regmap_read(regmap, 0x4, &val);
        if (val == 0x12) {
                slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
                mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
@@ -574,7 +574,6 @@ static struct platform_driver lcc_msm8960_driver = {
        .remove         = lcc_msm8960_remove,
        .driver         = {
                .name   = "lcc-msm8960",
-               .owner  = THIS_MODULE,
                .of_match_table = lcc_msm8960_match_table,
        },
 };
index 6ef8963..d216406 100644 (file)
@@ -84,7 +84,7 @@ static int ti_fapll_enable(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       v |= (1 << FAPLL_MAIN_PLLEN);
+       v |= FAPLL_MAIN_PLLEN;
        writel_relaxed(v, fd->base);
 
        return 0;
@@ -95,7 +95,7 @@ static void ti_fapll_disable(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       v &= ~(1 << FAPLL_MAIN_PLLEN);
+       v &= ~FAPLL_MAIN_PLLEN;
        writel_relaxed(v, fd->base);
 }
 
@@ -104,7 +104,7 @@ static int ti_fapll_is_enabled(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       return v & (1 << FAPLL_MAIN_PLLEN);
+       return v & FAPLL_MAIN_PLLEN;
 }
 
 static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
index 1c2506f..a0b036c 100644 (file)
@@ -63,6 +63,11 @@ config VT8500_TIMER
 config CADENCE_TTC_TIMER
        bool
 
+config ASM9260_TIMER
+       bool
+       select CLKSRC_MMIO
+       select CLKSRC_OF
+
 config CLKSRC_NOMADIK_MTU
        bool
        depends on (ARCH_NOMADIK || ARCH_U8500)
@@ -187,6 +192,7 @@ config SYS_SUPPORTS_EM_STI
 config SH_TIMER_CMT
        bool "Renesas CMT timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_CMT
        help
          This enables build of a clocksource and clockevent driver for
@@ -196,6 +202,7 @@ config SH_TIMER_CMT
 config SH_TIMER_MTU2
        bool "Renesas MTU2 timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_MTU2
        help
          This enables build of a clockevent driver for the Multi-Function
@@ -205,6 +212,7 @@ config SH_TIMER_MTU2
 config SH_TIMER_TMU
        bool "Renesas TMU timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_TMU
        help
          This enables build of a clocksource and clockevent driver for
@@ -245,15 +253,4 @@ config CLKSRC_PXA
        help
          This enables OST0 support available on PXA and SA-11x0
          platforms.
-
-config ASM9260_TIMER
-       bool "Alphascale ASM9260 timer driver"
-       depends on GENERIC_CLOCKEVENTS
-       select CLKSRC_MMIO
-       select CLKSRC_OF
-       default y if MACH_ASM9260
-       help
-         This enables build of a clocksource and clockevent driver for
-         the 32-bit System Timer hardware available on a Alphascale ASM9260.
-
 endmenu
index 32a3d25..68ab423 100644 (file)
@@ -224,6 +224,8 @@ static void __init mtk_timer_init(struct device_node *node)
        }
        rate = clk_get_rate(clk);
 
+       mtk_timer_global_reset(evt);
+
        if (request_irq(evt->dev.irq, mtk_timer_interrupt,
                        IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) {
                pr_warn("failed to setup irq %d\n", evt->dev.irq);
@@ -232,8 +234,6 @@ static void __init mtk_timer_init(struct device_node *node)
 
        evt->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
-       mtk_timer_global_reset(evt);
-
        /* Configure clock source */
        mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN);
        clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC),
@@ -241,10 +241,11 @@ static void __init mtk_timer_init(struct device_node *node)
 
        /* Configure clock event */
        mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT);
-       mtk_timer_enable_irq(evt, GPT_CLK_EVT);
-
        clockevents_config_and_register(&evt->dev, rate, 0x3,
                                        0xffffffff);
+
+       mtk_timer_enable_irq(evt, GPT_CLK_EVT);
+
        return;
 
 err_clk_disable:
index 941f3f3..d9438af 100644 (file)
@@ -163,7 +163,7 @@ static struct irqaction pxa_ost0_irq = {
        .dev_id         = &ckevt_pxa_osmr0,
 };
 
-static void pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
+static void __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
 {
        timer_writel(0, OIER);
        timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
index bba62f9..ec57ba2 100644 (file)
@@ -225,12 +225,12 @@ static int __init efm32_clockevent_init(struct device_node *np)
        clock_event_ddata.base = base;
        clock_event_ddata.periodic_top = DIV_ROUND_CLOSEST(rate, 1024 * HZ);
 
-       setup_irq(irq, &efm32_clock_event_irq);
-
        clockevents_config_and_register(&clock_event_ddata.evtdev,
                                        DIV_ROUND_CLOSEST(rate, 1024),
                                        0xf, 0xffff);
 
+       setup_irq(irq, &efm32_clock_event_irq);
+
        return 0;
 
 err_get_irq:
index 0226844..58597fb 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/irq.h>
 #include <linux/irqreturn.h>
 #include <linux/reset.h>
-#include <linux/sched_clock.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -137,11 +136,6 @@ static struct irqaction sun5i_timer_irq = {
        .dev_id = &sun5i_clockevent,
 };
 
-static u64 sun5i_timer_sched_read(void)
-{
-       return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1));
-}
-
 static void __init sun5i_timer_init(struct device_node *node)
 {
        struct reset_control *rstc;
@@ -172,16 +166,11 @@ static void __init sun5i_timer_init(struct device_node *node)
        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
               timer_base + TIMER_CTL_REG(1));
 
-       sched_clock_register(sun5i_timer_sched_read, 32, rate);
        clocksource_mmio_init(timer_base + TIMER_CNTVAL_LO_REG(1), node->name,
                              rate, 340, 32, clocksource_mmio_readl_down);
 
        ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
-       ret = setup_irq(irq, &sun5i_timer_irq);
-       if (ret)
-               pr_warn("failed to setup irq %d\n", irq);
-
        /* Enable timer0 interrupt */
        val = readl(timer_base + TIMER_IRQ_EN_REG);
        writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
@@ -191,6 +180,10 @@ static void __init sun5i_timer_init(struct device_node *node)
 
        clockevents_config_and_register(&sun5i_clockevent, rate,
                                        TIMER_SYNC_TICKS, 0xffffffff);
+
+       ret = setup_irq(irq, &sun5i_timer_irq);
+       if (ret)
+               pr_warn("failed to setup irq %d\n", irq);
 }
 CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
                       sun5i_timer_init);
index 5e98c6b..82d2fbb 100644 (file)
@@ -159,7 +159,7 @@ static struct cpufreq_driver exynos_driver = {
 
 static int exynos_cpufreq_probe(struct platform_device *pdev)
 {
-       struct device_node *cpus, *np;
+       struct device_node *cpu0;
        int ret = -EINVAL;
 
        exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
@@ -206,28 +206,19 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
        if (ret)
                goto err_cpufreq_reg;
 
-       cpus = of_find_node_by_path("/cpus");
-       if (!cpus) {
-               pr_err("failed to find cpus node\n");
+       cpu0 = of_get_cpu_node(0, NULL);
+       if (!cpu0) {
+               pr_err("failed to find cpu0 node\n");
                return 0;
        }
 
-       np = of_get_next_child(cpus, NULL);
-       if (!np) {
-               pr_err("failed to find cpus child node\n");
-               of_node_put(cpus);
-               return 0;
-       }
-
-       if (of_find_property(np, "#cooling-cells", NULL)) {
-               cdev = of_cpufreq_cooling_register(np,
+       if (of_find_property(cpu0, "#cooling-cells", NULL)) {
+               cdev = of_cpufreq_cooling_register(cpu0,
                                                   cpu_present_mask);
                if (IS_ERR(cdev))
                        pr_err("running cpufreq without cooling device: %ld\n",
                               PTR_ERR(cdev));
        }
-       of_node_put(np);
-       of_node_put(cpus);
 
        return 0;
 
index bee5df7..7cb4b76 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/smp.h>
 #include <sysdev/fsl_soc.h>
 
+#include <asm/smp.h>   /* for get_hard_smp_processor_id() in UP configs */
+
 /**
  * struct cpu_data - per CPU data struct
  * @parent: the parent node of cpu clock
index 38e6861..980151f 100644 (file)
@@ -37,11 +37,11 @@ static int mvebu_v7_enter_idle(struct cpuidle_device *dev,
                deepidle = true;
 
        ret = mvebu_v7_cpu_suspend(deepidle);
+       cpu_pm_exit();
+
        if (ret)
                return ret;
 
-       cpu_pm_exit();
-
        return index;
 }
 
@@ -50,17 +50,17 @@ static struct cpuidle_driver armadaxp_idle_driver = {
        .states[0]              = ARM_CPUIDLE_WFI_STATE,
        .states[1]              = {
                .enter                  = mvebu_v7_enter_idle,
-               .exit_latency           = 10,
+               .exit_latency           = 100,
                .power_usage            = 50,
-               .target_residency       = 100,
+               .target_residency       = 1000,
                .name                   = "MV CPU IDLE",
                .desc                   = "CPU power down",
        },
        .states[2]              = {
                .enter                  = mvebu_v7_enter_idle,
-               .exit_latency           = 100,
+               .exit_latency           = 1000,
                .power_usage            = 5,
-               .target_residency       = 1000,
+               .target_residency       = 10000,
                .flags                  = MVEBU_V7_FLAG_DEEP_IDLE,
                .name                   = "MV CPU DEEP IDLE",
                .desc                   = "CPU and L2 Fabric power down",
index 4d53458..080bd2d 100644 (file)
@@ -44,6 +44,12 @@ void disable_cpuidle(void)
        off = 1;
 }
 
+bool cpuidle_not_available(struct cpuidle_driver *drv,
+                          struct cpuidle_device *dev)
+{
+       return off || !initialized || !drv || !dev || !dev->enabled;
+}
+
 /**
  * cpuidle_play_dead - cpu off-lining
  *
@@ -66,14 +72,8 @@ int cpuidle_play_dead(void)
        return -ENODEV;
 }
 
-/**
- * cpuidle_find_deepest_state - Find deepest state meeting specific conditions.
- * @drv: cpuidle driver for the given CPU.
- * @dev: cpuidle device for the given CPU.
- * @freeze: Whether or not the state should be suitable for suspend-to-idle.
- */
-static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
-                                     struct cpuidle_device *dev, bool freeze)
+static int find_deepest_state(struct cpuidle_driver *drv,
+                             struct cpuidle_device *dev, bool freeze)
 {
        unsigned int latency_req = 0;
        int i, ret = freeze ? -1 : CPUIDLE_DRIVER_STATE_START - 1;
@@ -92,6 +92,17 @@ static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
        return ret;
 }
 
+/**
+ * cpuidle_find_deepest_state - Find the deepest available idle state.
+ * @drv: cpuidle driver for the given CPU.
+ * @dev: cpuidle device for the given CPU.
+ */
+int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                              struct cpuidle_device *dev)
+{
+       return find_deepest_state(drv, dev, false);
+}
+
 static void enter_freeze_proper(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev, int index)
 {
@@ -113,15 +124,14 @@ static void enter_freeze_proper(struct cpuidle_driver *drv,
 
 /**
  * cpuidle_enter_freeze - Enter an idle state suitable for suspend-to-idle.
+ * @drv: cpuidle driver for the given CPU.
+ * @dev: cpuidle device for the given CPU.
  *
  * If there are states with the ->enter_freeze callback, find the deepest of
- * them and enter it with frozen tick.  Otherwise, find the deepest state
- * available and enter it normally.
+ * them and enter it with frozen tick.
  */
-void cpuidle_enter_freeze(void)
+int cpuidle_enter_freeze(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
-       struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
-       struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int index;
 
        /*
@@ -129,24 +139,11 @@ void cpuidle_enter_freeze(void)
         * that interrupts won't be enabled when it exits and allows the tick to
         * be frozen safely.
         */
-       index = cpuidle_find_deepest_state(drv, dev, true);
-       if (index >= 0) {
-               enter_freeze_proper(drv, dev, index);
-               return;
-       }
-
-       /*
-        * It is not safe to freeze the tick, find the deepest state available
-        * at all and try to enter it normally.
-        */
-       index = cpuidle_find_deepest_state(drv, dev, false);
+       index = find_deepest_state(drv, dev, true);
        if (index >= 0)
-               cpuidle_enter(drv, dev, index);
-       else
-               arch_cpu_idle();
+               enter_freeze_proper(drv, dev, index);
 
-       /* Interrupts are enabled again here. */
-       local_irq_disable();
+       return index;
 }
 
 /**
@@ -205,12 +202,6 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
  */
 int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
-       if (off || !initialized)
-               return -ENODEV;
-
-       if (!drv || !dev || !dev->enabled)
-               return -EBUSY;
-
        return cpuidle_curr_governor->select(drv, dev);
 }
 
index e554111..50ef8bd 100644 (file)
@@ -159,6 +159,9 @@ fence_wait_timeout(struct fence *fence, bool intr, signed long timeout)
        if (WARN_ON(timeout < 0))
                return -EINVAL;
 
+       if (timeout == 0)
+               return fence_is_signaled(fence);
+
        trace_fence_wait_start(fence);
        ret = fence->ops->wait(fence, intr, timeout);
        trace_fence_wait_end(fence);
index 3c97c8f..39920d7 100644 (file)
@@ -327,6 +327,9 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
        unsigned seq, shared_count, i = 0;
        long ret = timeout;
 
+       if (!timeout)
+               return reservation_object_test_signaled_rcu(obj, wait_all);
+
 retry:
        fence = NULL;
        shared_count = 0;
@@ -402,8 +405,6 @@ reservation_object_test_signaled_single(struct fence *passed_fence)
        int ret = 1;
 
        if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
-               int ret;
-
                fence = fence_get_rcu(lfence);
                if (!fence)
                        return -1;
index 4a5fd24..83aa55d 100644 (file)
 
 #define DRIVER_NAME    "pl08xdmac"
 
+#define PL80X_DMA_BUSWIDTHS \
+       BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
+       BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)
+
 static struct amba_driver pl08x_amba_driver;
 struct pl08x_driver_data;
 
@@ -2070,6 +2076,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->memcpy.device_pause = pl08x_pause;
        pl08x->memcpy.device_resume = pl08x_resume;
        pl08x->memcpy.device_terminate_all = pl08x_terminate_all;
+       pl08x->memcpy.src_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->memcpy.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->memcpy.directions = BIT(DMA_MEM_TO_MEM);
+       pl08x->memcpy.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
        /* Initialize slave engine */
        dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
@@ -2086,6 +2096,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->slave.device_pause = pl08x_pause;
        pl08x->slave.device_resume = pl08x_resume;
        pl08x->slave.device_terminate_all = pl08x_terminate_all;
+       pl08x->slave.src_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->slave.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       pl08x->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
        /* Get the platform data */
        pl08x->pd = dev_get_platdata(&adev->dev);
index 1e1a4c5..0b4fc6f 100644 (file)
@@ -238,93 +238,126 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
 }
 
 /*
- * atc_get_current_descriptors -
- * locate the descriptor which equal to physical address in DSCR
- * @atchan: the channel we want to start
- * @dscr_addr: physical descriptor address in DSCR
+ * atc_get_desc_by_cookie - get the descriptor of a cookie
+ * @atchan: the DMA channel
+ * @cookie: the cookie to get the descriptor for
  */
-static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
-                                                       u32 dscr_addr)
+static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
+                                               dma_cookie_t cookie)
 {
-       struct at_desc  *desc, *_desc, *child, *desc_cur = NULL;
+       struct at_desc *desc, *_desc;
 
-       list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
-               if (desc->lli.dscr == dscr_addr) {
-                       desc_cur = desc;
-                       break;
-               }
+       list_for_each_entry_safe(desc, _desc, &atchan->queue, desc_node) {
+               if (desc->txd.cookie == cookie)
+                       return desc;
+       }
 
-               list_for_each_entry(child, &desc->tx_list, desc_node) {
-                       if (child->lli.dscr == dscr_addr) {
-                               desc_cur = child;
-                               break;
-                       }
-               }
+       list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
+               if (desc->txd.cookie == cookie)
+                       return desc;
        }
 
-       return desc_cur;
+       return NULL;
 }
 
-/*
- * atc_get_bytes_left -
- * Get the number of bytes residue in dma buffer,
- * @chan: the channel we want to start
+/**
+ * atc_calc_bytes_left - calculates the number of bytes left according to the
+ * value read from CTRLA.
+ *
+ * @current_len: the number of bytes left before reading CTRLA
+ * @ctrla: the value of CTRLA
+ * @desc: the descriptor containing the transfer width
+ */
+static inline int atc_calc_bytes_left(int current_len, u32 ctrla,
+                                       struct at_desc *desc)
+{
+       return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
+}
+
+/**
+ * atc_calc_bytes_left_from_reg - calculates the number of bytes left according
+ * to the current value of CTRLA.
+ *
+ * @current_len: the number of bytes left before reading CTRLA
+ * @atchan: the channel to read CTRLA for
+ * @desc: the descriptor containing the transfer width
+ */
+static inline int atc_calc_bytes_left_from_reg(int current_len,
+                       struct at_dma_chan *atchan, struct at_desc *desc)
+{
+       u32 ctrla = channel_readl(atchan, CTRLA);
+
+       return atc_calc_bytes_left(current_len, ctrla, desc);
+}
+
+/**
+ * atc_get_bytes_left - get the number of bytes residue for a cookie
+ * @chan: DMA channel
+ * @cookie: transaction identifier to check status of
  */
-static int atc_get_bytes_left(struct dma_chan *chan)
+static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
-       struct at_dma           *atdma = to_at_dma(chan->device);
-       int     chan_id = atchan->chan_common.chan_id;
        struct at_desc *desc_first = atc_first_active(atchan);
-       struct at_desc *desc_cur;
-       int ret = 0, count = 0;
+       struct at_desc *desc;
+       int ret;
+       u32 ctrla, dscr;
 
        /*
-        * Initialize necessary values in the first time.
-        * remain_desc record remain desc length.
+        * If the cookie doesn't match to the currently running transfer then
+        * we can return the total length of the associated DMA transfer,
+        * because it is still queued.
         */
-       if (atchan->remain_desc == 0)
-               /* First descriptor embedds the transaction length */
-               atchan->remain_desc = desc_first->len;
+       desc = atc_get_desc_by_cookie(atchan, cookie);
+       if (desc == NULL)
+               return -EINVAL;
+       else if (desc != desc_first)
+               return desc->total_len;
 
-       /*
-        * This happens when current descriptor transfer complete.
-        * The residual buffer size should reduce current descriptor length.
-        */
-       if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
-               clear_bit(ATC_IS_BTC, &atchan->status);
-               desc_cur = atc_get_current_descriptors(atchan,
-                                               channel_readl(atchan, DSCR));
-               if (!desc_cur) {
-                       ret = -EINVAL;
-                       goto out;
-               }
+       /* cookie matches to the currently running transfer */
+       ret = desc_first->total_len;
 
-               count = (desc_cur->lli.ctrla & ATC_BTSIZE_MAX)
-                       << desc_first->tx_width;
-               if (atchan->remain_desc < count) {
-                       ret = -EINVAL;
-                       goto out;
+       if (desc_first->lli.dscr) {
+               /* hardware linked list transfer */
+
+               /*
+                * Calculate the residue by removing the length of the child
+                * descriptors already transferred from the total length.
+                * To get the current child descriptor we can use the value of
+                * the channel's DSCR register and compare it against the value
+                * of the hardware linked list structure of each child
+                * descriptor.
+                */
+
+               ctrla = channel_readl(atchan, CTRLA);
+               rmb(); /* ensure CTRLA is read before DSCR */
+               dscr = channel_readl(atchan, DSCR);
+
+               /* for the first descriptor we can be more accurate */
+               if (desc_first->lli.dscr == dscr)
+                       return atc_calc_bytes_left(ret, ctrla, desc_first);
+
+               ret -= desc_first->len;
+               list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
+                       if (desc->lli.dscr == dscr)
+                               break;
+
+                       ret -= desc->len;
                }
 
-               atchan->remain_desc -= count;
-               ret = atchan->remain_desc;
-       } else {
                /*
-                * Get residual bytes when current
-                * descriptor transfer in progress.
+                * For the last descriptor in the chain we can calculate
+                * the remaining bytes using the channel's register.
+                * Note that the transfer width of the first and last
+                * descriptor may differ.
                 */
-               count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX)
-                               << (desc_first->tx_width);
-               ret = atchan->remain_desc - count;
+               if (!desc->lli.dscr)
+                       ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
+       } else {
+               /* single transfer */
+               ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
        }
-       /*
-        * Check fifo empty.
-        */
-       if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id)))
-               atc_issue_pending(chan);
 
-out:
        return ret;
 }
 
@@ -539,8 +572,6 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
                                        /* Give information to tasklet */
                                        set_bit(ATC_IS_ERROR, &atchan->status);
                                }
-                               if (pending & AT_DMA_BTC(i))
-                                       set_bit(ATC_IS_BTC, &atchan->status);
                                tasklet_schedule(&atchan->tasklet);
                                ret = IRQ_HANDLED;
                        }
@@ -653,14 +684,18 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                desc->lli.ctrlb = ctrlb;
 
                desc->txd.cookie = 0;
+               desc->len = xfer_count << src_width;
 
                atc_desc_chain(&first, &prev, desc);
        }
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = len;
+       first->total_len = len;
+
+       /* set transfer width for the calculation of the residue */
        first->tx_width = src_width;
+       prev->tx_width = src_width;
 
        /* set end-of-link to the last link descriptor of list*/
        set_desc_eol(desc);
@@ -752,6 +787,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | ATC_SRC_WIDTH(mem_width)
                                        | len >> mem_width;
                        desc->lli.ctrlb = ctrlb;
+                       desc->len = len;
 
                        atc_desc_chain(&first, &prev, desc);
                        total_len += len;
@@ -792,6 +828,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | ATC_DST_WIDTH(mem_width)
                                        | len >> reg_width;
                        desc->lli.ctrlb = ctrlb;
+                       desc->len = len;
 
                        atc_desc_chain(&first, &prev, desc);
                        total_len += len;
@@ -806,8 +843,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = total_len;
+       first->total_len = total_len;
+
+       /* set transfer width for the calculation of the residue */
        first->tx_width = reg_width;
+       prev->tx_width = reg_width;
 
        /* first link descriptor of list is responsible of flags */
        first->txd.flags = flags; /* client is in control of this ack */
@@ -872,6 +912,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
                                | ATC_FC_MEM2PER
                                | ATC_SIF(atchan->mem_if)
                                | ATC_DIF(atchan->per_if);
+               desc->len = period_len;
                break;
 
        case DMA_DEV_TO_MEM:
@@ -883,6 +924,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
                                | ATC_FC_PER2MEM
                                | ATC_SIF(atchan->per_if)
                                | ATC_DIF(atchan->mem_if);
+               desc->len = period_len;
                break;
 
        default:
@@ -964,7 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = buf_len;
+       first->total_len = buf_len;
        first->tx_width = reg_width;
 
        return &first->txd;
@@ -1118,7 +1160,7 @@ atc_tx_status(struct dma_chan *chan,
        spin_lock_irqsave(&atchan->lock, flags);
 
        /*  Get number of bytes left in the active transactions */
-       bytes = atc_get_bytes_left(chan);
+       bytes = atc_get_bytes_left(chan, cookie);
 
        spin_unlock_irqrestore(&atchan->lock, flags);
 
@@ -1214,7 +1256,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 
        spin_lock_irqsave(&atchan->lock, flags);
        atchan->descs_allocated = i;
-       atchan->remain_desc = 0;
        list_splice(&tmp_list, &atchan->free_list);
        dma_cookie_init(chan);
        spin_unlock_irqrestore(&atchan->lock, flags);
@@ -1257,7 +1298,6 @@ static void atc_free_chan_resources(struct dma_chan *chan)
        list_splice_init(&atchan->free_list, &list);
        atchan->descs_allocated = 0;
        atchan->status = 0;
-       atchan->remain_desc = 0;
 
        dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
 }
index d6bba6c..2727ca5 100644 (file)
@@ -181,8 +181,9 @@ struct at_lli {
  * @at_lli: hardware lli structure
  * @txd: support for the async_tx api
  * @desc_node: node on the channed descriptors list
- * @len: total transaction bytecount
+ * @len: descriptor byte count
  * @tx_width: transfer width
+ * @total_len: total transaction byte count
  */
 struct at_desc {
        /* FIRST values the hardware uses */
@@ -194,6 +195,7 @@ struct at_desc {
        struct list_head                desc_node;
        size_t                          len;
        u32                             tx_width;
+       size_t                          total_len;
 };
 
 static inline struct at_desc *
@@ -213,7 +215,6 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
 enum atc_status {
        ATC_IS_ERROR = 0,
        ATC_IS_PAUSED = 1,
-       ATC_IS_BTC = 2,
        ATC_IS_CYCLIC = 24,
 };
 
@@ -231,7 +232,6 @@ enum atc_status {
  * @save_cfg: configuration register that is saved on suspend/resume cycle
  * @save_dscr: for cyclic operations, preserve next descriptor address in
  *             the cyclic list on suspend/resume cycle
- * @remain_desc: to save remain desc length
  * @dma_sconfig: configuration for slave transfers, passed via
  * .device_config
  * @lock: serializes enqueue/dequeue operations to descriptors lists
@@ -251,7 +251,6 @@ struct at_dma_chan {
        struct tasklet_struct   tasklet;
        u32                     save_cfg;
        u32                     save_dscr;
-       u32                     remain_desc;
        struct dma_slave_config dma_sconfig;
 
        spinlock_t              lock;
index 09e2825..d9891d3 100644 (file)
@@ -664,7 +664,6 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
        struct at_xdmac_desc    *first = NULL, *prev = NULL;
        unsigned int            periods = buf_len / period_len;
        int                     i;
-       u32                     cfg;
 
        dev_dbg(chan2dev(chan), "%s: buf_addr=%pad, buf_len=%zd, period_len=%zd, dir=%s, flags=0x%lx\n",
                __func__, &buf_addr, buf_len, period_len,
@@ -700,17 +699,17 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
                if (direction == DMA_DEV_TO_MEM) {
                        desc->lld.mbr_sa = atchan->per_src_addr;
                        desc->lld.mbr_da = buf_addr + i * period_len;
-                       cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
+                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
                } else {
                        desc->lld.mbr_sa = buf_addr + i * period_len;
                        desc->lld.mbr_da = atchan->per_dst_addr;
-                       cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
+                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
                }
                desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1
                        | AT_XDMAC_MBR_UBC_NDEN
                        | AT_XDMAC_MBR_UBC_NSEN
                        | AT_XDMAC_MBR_UBC_NDE
-                       | period_len >> at_xdmac_get_dwidth(cfg);
+                       | period_len >> at_xdmac_get_dwidth(desc->lld.mbr_cfg);
 
                dev_dbg(chan2dev(chan),
                         "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
index 0723096..c92d6a7 100644 (file)
@@ -475,6 +475,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
         * c->desc is NULL and exit.)
         */
        if (c->desc) {
+               bcm2835_dma_desc_free(&c->desc->vd);
                c->desc = NULL;
                bcm2835_dma_abort(c->chan_base);
 
index 4527a3e..8488441 100644 (file)
@@ -511,6 +511,9 @@ static void jz4740_dma_desc_free(struct virt_dma_desc *vdesc)
        kfree(container_of(vdesc, struct jz4740_dma_desc, vdesc));
 }
 
+#define JZ4740_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
 static int jz4740_dma_probe(struct platform_device *pdev)
 {
        struct jz4740_dmaengine_chan *chan;
@@ -548,6 +551,10 @@ static int jz4740_dma_probe(struct platform_device *pdev)
        dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic;
        dd->device_config = jz4740_dma_slave_config;
        dd->device_terminate_all = jz4740_dma_terminate_all;
+       dd->src_addr_widths = JZ4740_DMA_BUSWIDTHS;
+       dd->dst_addr_widths = JZ4740_DMA_BUSWIDTHS;
+       dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
        dd->dev = &pdev->dev;
        INIT_LIST_HEAD(&dd->channels);
 
index 455b7a4..a8ad052 100644 (file)
@@ -626,7 +626,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
        dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status);
 
        /* Check if we have any interrupt from the DMAC */
-       if (!status)
+       if (!status || !dw->in_use)
                return IRQ_NONE;
 
        /*
index 6565a36..b2c3ae0 100644 (file)
@@ -26,6 +26,8 @@
 
 #include "internal.h"
 
+#define DRV_NAME       "dw_dmac"
+
 static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
                                        struct of_dma *ofdma)
 {
@@ -284,7 +286,7 @@ static struct platform_driver dw_driver = {
        .remove         = dw_remove,
        .shutdown       = dw_shutdown,
        .driver = {
-               .name   = "dw_dmac",
+               .name   = DRV_NAME,
                .pm     = &dw_dev_pm_ops,
                .of_match_table = of_match_ptr(dw_dma_of_id_table),
                .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
@@ -305,3 +307,4 @@ module_exit(dw_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
+MODULE_ALIAS("platform:" DRV_NAME);
index 276157f..53dbd3b 100644 (file)
@@ -260,6 +260,13 @@ static int edma_terminate_all(struct dma_chan *chan)
         */
        if (echan->edesc) {
                int cyclic = echan->edesc->cyclic;
+
+               /*
+                * free the running request descriptor
+                * since it is not in any of the vdesc lists
+                */
+               edma_desc_free(&echan->edesc->vdesc);
+
                echan->edesc = NULL;
                edma_stop(echan->ch_num);
                /* Move the cyclic channel back to default queue */
index 18c0a13..66a0efb 100644 (file)
@@ -531,6 +531,10 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
                dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
        }
 
+       /* Set bits of CONFIG register with dynamic context switching */
+       if (readl(sdma->regs + SDMA_H_CONFIG) == 0)
+               writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+
        return ret ? 0 : -ETIMEDOUT;
 }
 
@@ -1394,9 +1398,6 @@ static int sdma_init(struct sdma_engine *sdma)
 
        writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
 
-       /* Set bits of CONFIG register with given context switching mode */
-       writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
-
        /* Initializes channel's priorities */
        sdma_set_channel_priority(&sdma->channel[0], 7);
 
index 77a6dcf..194ec20 100644 (file)
@@ -230,6 +230,10 @@ static bool is_bwd_noraid(struct pci_dev *pdev)
        switch (pdev->device) {
        case PCI_DEVICE_ID_INTEL_IOAT_BWD2:
        case PCI_DEVICE_ID_INTEL_IOAT_BWD3:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE0:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE1:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE2:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE3:
                return true;
        default:
                return false;
index 8926f27..eb41004 100644 (file)
@@ -219,6 +219,9 @@ static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id)
 
        while (dint) {
                i = __ffs(dint);
+               /* only handle interrupts belonging to pdma driver*/
+               if (i >= pdev->dma_channels)
+                       break;
                dint &= (dint - 1);
                phy = &pdev->phy[i];
                ret = mmp_pdma_chan_handler(irq, phy);
@@ -999,6 +1002,9 @@ static int mmp_pdma_probe(struct platform_device *op)
        struct resource *iores;
        int i, ret, irq = 0;
        int dma_channels = 0, irq_num = 0;
+       const enum dma_slave_buswidth widths =
+               DMA_SLAVE_BUSWIDTH_1_BYTE   | DMA_SLAVE_BUSWIDTH_2_BYTES |
+               DMA_SLAVE_BUSWIDTH_4_BYTES;
 
        pdev = devm_kzalloc(&op->dev, sizeof(*pdev), GFP_KERNEL);
        if (!pdev)
@@ -1066,6 +1072,10 @@ static int mmp_pdma_probe(struct platform_device *op)
        pdev->device.device_config = mmp_pdma_config;
        pdev->device.device_terminate_all = mmp_pdma_terminate_all;
        pdev->device.copy_align = PDMA_ALIGNMENT;
+       pdev->device.src_addr_widths = widths;
+       pdev->device.dst_addr_widths = widths;
+       pdev->device.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+       pdev->device.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
 
        if (pdev->dev->coherent_dma_mask)
                dma_set_mask(pdev->dev, pdev->dev->coherent_dma_mask);
index 70c2fa9..b6f4e1f 100644 (file)
@@ -110,7 +110,7 @@ struct mmp_tdma_chan {
        struct tasklet_struct           tasklet;
 
        struct mmp_tdma_desc            *desc_arr;
-       phys_addr_t                     desc_arr_phys;
+       dma_addr_t                      desc_arr_phys;
        int                             desc_num;
        enum dma_transfer_direction     dir;
        dma_addr_t                      dev_addr;
@@ -166,9 +166,12 @@ static void mmp_tdma_enable_chan(struct mmp_tdma_chan *tdmac)
 static int mmp_tdma_disable_chan(struct dma_chan *chan)
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+       u32 tdcr;
 
-       writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
-                                       tdmac->reg_base + TDCR);
+       tdcr = readl(tdmac->reg_base + TDCR);
+       tdcr |= TDCR_ABR;
+       tdcr &= ~TDCR_CHANEN;
+       writel(tdcr, tdmac->reg_base + TDCR);
 
        tdmac->status = DMA_COMPLETE;
 
@@ -296,12 +299,27 @@ static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
        return -EAGAIN;
 }
 
+static size_t mmp_tdma_get_pos(struct mmp_tdma_chan *tdmac)
+{
+       size_t reg;
+
+       if (tdmac->idx == 0) {
+               reg = __raw_readl(tdmac->reg_base + TDSAR);
+               reg -= tdmac->desc_arr[0].src_addr;
+       } else if (tdmac->idx == 1) {
+               reg = __raw_readl(tdmac->reg_base + TDDAR);
+               reg -= tdmac->desc_arr[0].dst_addr;
+       } else
+               return -EINVAL;
+
+       return reg;
+}
+
 static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
 {
        struct mmp_tdma_chan *tdmac = dev_id;
 
        if (mmp_tdma_clear_chan_irq(tdmac) == 0) {
-               tdmac->pos = (tdmac->pos + tdmac->period_len) % tdmac->buf_len;
                tasklet_schedule(&tdmac->tasklet);
                return IRQ_HANDLED;
        } else
@@ -343,7 +361,7 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
        int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
 
        gpool = tdmac->pool;
-       if (tdmac->desc_arr)
+       if (gpool && tdmac->desc_arr)
                gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
                                size);
        tdmac->desc_arr = NULL;
@@ -499,6 +517,7 @@ static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
 
+       tdmac->pos = mmp_tdma_get_pos(tdmac);
        dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
                         tdmac->buf_len - tdmac->pos);
 
@@ -610,7 +629,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
        int i, ret;
        int irq = 0, irq_num = 0;
        int chan_num = TDMA_CHANNEL_NUM;
-       struct gen_pool *pool;
+       struct gen_pool *pool = NULL;
 
        of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
        if (of_id)
index 15cab7d..b463410 100644 (file)
@@ -193,8 +193,10 @@ static int moxart_terminate_all(struct dma_chan *chan)
 
        spin_lock_irqsave(&ch->vc.lock, flags);
 
-       if (ch->desc)
+       if (ch->desc) {
+               moxart_dma_desc_free(&ch->desc->vd);
                ch->desc = NULL;
+       }
 
        ctrl = readl(ch->base + REG_OFF_CTRL);
        ctrl &= ~(APB_DMA_ENABLE | APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
index 7dd6dd1..167dbaf 100644 (file)
@@ -981,6 +981,7 @@ static int omap_dma_terminate_all(struct dma_chan *chan)
         * c->desc is NULL and exit.)
         */
        if (c->desc) {
+               omap_dma_desc_free(&c->desc->vd);
                c->desc = NULL;
                /* Avoid stopping the dma twice */
                if (!c->paused)
index d7a33b3..9c914d6 100644 (file)
@@ -162,9 +162,9 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = {
        [BAM_P_IRQ_STTS]        = { 0x1010, 0x1000, 0x00, 0x00 },
        [BAM_P_IRQ_CLR]         = { 0x1014, 0x1000, 0x00, 0x00 },
        [BAM_P_IRQ_EN]          = { 0x1018, 0x1000, 0x00, 0x00 },
-       [BAM_P_EVNT_DEST_ADDR]  = { 0x102C, 0x00, 0x1000, 0x00 },
-       [BAM_P_EVNT_REG]        = { 0x1018, 0x00, 0x1000, 0x00 },
-       [BAM_P_SW_OFSTS]        = { 0x1000, 0x00, 0x1000, 0x00 },
+       [BAM_P_EVNT_DEST_ADDR]  = { 0x182C, 0x00, 0x1000, 0x00 },
+       [BAM_P_EVNT_REG]        = { 0x1818, 0x00, 0x1000, 0x00 },
+       [BAM_P_SW_OFSTS]        = { 0x1800, 0x00, 0x1000, 0x00 },
        [BAM_P_DATA_FIFO_ADDR]  = { 0x1824, 0x00, 0x1000, 0x00 },
        [BAM_P_DESC_FIFO_ADDR]  = { 0x181C, 0x00, 0x1000, 0x00 },
        [BAM_P_EVNT_GEN_TRSHLD] = { 0x1828, 0x00, 0x1000, 0x00 },
@@ -1143,6 +1143,10 @@ static int bam_dma_probe(struct platform_device *pdev)
        dma_cap_set(DMA_SLAVE, bdev->common.cap_mask);
 
        /* initialize dmaengine apis */
+       bdev->common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       bdev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+       bdev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       bdev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
        bdev->common.device_alloc_chan_resources = bam_alloc_chan;
        bdev->common.device_free_chan_resources = bam_free_chan;
        bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
index b2431aa..9f1d4c7 100644 (file)
@@ -582,15 +582,12 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
        }
 }
 
-static void sh_dmae_shutdown(struct platform_device *pdev)
-{
-       struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
-       sh_dmae_ctl_stop(shdev);
-}
-
 #ifdef CONFIG_PM
 static int sh_dmae_runtime_suspend(struct device *dev)
 {
+       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+       sh_dmae_ctl_stop(shdev);
        return 0;
 }
 
@@ -605,6 +602,9 @@ static int sh_dmae_runtime_resume(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int sh_dmae_suspend(struct device *dev)
 {
+       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+       sh_dmae_ctl_stop(shdev);
        return 0;
 }
 
@@ -929,13 +929,12 @@ static int sh_dmae_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver sh_dmae_driver = {
-       .driver         = {
+       .driver         = {
                .pm     = &sh_dmae_pm,
                .name   = SH_DMAE_DRV_NAME,
                .of_match_table = sh_dmae_of_match,
        },
        .remove         = sh_dmae_remove,
-       .shutdown       = sh_dmae_shutdown,
 };
 
 static int __init sh_dmae_init(void)
index c5f7b4e..2eebd28 100644 (file)
@@ -78,7 +78,7 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
  *     We have to be cautious here. We have seen BIOSes with DMI pointers
  *     pointing to completely the wrong place for example
  */
-static void dmi_table(u8 *buf, int len, int num,
+static void dmi_table(u8 *buf, u32 len, int num,
                      void (*decode)(const struct dmi_header *, void *),
                      void *private_data)
 {
@@ -86,18 +86,15 @@ static void dmi_table(u8 *buf, int len, int num,
        int i = 0;
 
        /*
-        *      Stop when we see all the items the table claimed to have
-        *      OR we run off the end of the table (also happens)
+        * Stop when we have seen all the items the table claimed to have
+        * (SMBIOS < 3.0 only) OR we reach an end-of-table marker OR we run
+        * off the end of the table (should never happen but sometimes does
+        * on bogus implementations.)
         */
-       while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
+       while ((!num || i < num) &&
+              (data - buf + sizeof(struct dmi_header)) <= len) {
                const struct dmi_header *dm = (const struct dmi_header *)data;
 
-               /*
-                * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
-                */
-               if (dm->type == DMI_ENTRY_END_OF_TABLE)
-                       break;
-
                /*
                 *  We want to know the total length (formatted area and
                 *  strings) before decoding to make sure we won't run off the
@@ -108,13 +105,20 @@ static void dmi_table(u8 *buf, int len, int num,
                        data++;
                if (data - buf < len - 1)
                        decode(dm, private_data);
+
+               /*
+                * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
+                */
+               if (dm->type == DMI_ENTRY_END_OF_TABLE)
+                       break;
+
                data += 2;
                i++;
        }
 }
 
 static phys_addr_t dmi_base;
-static u16 dmi_len;
+static u32 dmi_len;
 static u16 dmi_num;
 
 static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
@@ -528,21 +532,10 @@ static int __init dmi_smbios3_present(const u8 *buf)
        if (memcmp(buf, "_SM3_", 5) == 0 &&
            buf[6] < 32 && dmi_checksum(buf, buf[6])) {
                dmi_ver = get_unaligned_be16(buf + 7);
+               dmi_num = 0;                    /* No longer specified */
                dmi_len = get_unaligned_le32(buf + 12);
                dmi_base = get_unaligned_le64(buf + 16);
 
-               /*
-                * The 64-bit SMBIOS 3.0 entry point no longer has a field
-                * containing the number of structures present in the table.
-                * Instead, it defines the table size as a maximum size, and
-                * relies on the end-of-table structure type (#127) to be used
-                * to signal the end of the table.
-                * So let's define dmi_num as an upper bound as well: each
-                * structure has a 4 byte header, so dmi_len / 4 is an upper
-                * bound for the number of structures in the table.
-                */
-               dmi_num = dmi_len / 4;
-
                if (dmi_walk_early(dmi_decode) == 0) {
                        pr_info("SMBIOS %d.%d present.\n",
                                dmi_ver >> 8, dmi_ver & 0xFF);
index 2fe1950..f07d4a6 100644 (file)
@@ -179,12 +179,12 @@ again:
                start = desc->phys_addr;
                end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
 
-               if ((start + size) > end || (start + size) > max)
-                       continue;
-
-               if (end - size > max)
+               if (end > max)
                        end = max;
 
+               if ((start + size) > end)
+                       continue;
+
                if (round_down(end - size, align) < start)
                        continue;
 
index a6952ba..a65b751 100644 (file)
@@ -334,7 +334,7 @@ static struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
-static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
+static struct of_device_id mpc8xxx_gpio_ids[] = {
        { .compatible = "fsl,mpc8349-gpio", },
        { .compatible = "fsl,mpc8572-gpio", },
        { .compatible = "fsl,mpc8610-gpio", },
index 257e298..045a952 100644 (file)
@@ -219,7 +219,7 @@ static int syscon_gpio_probe(struct platform_device *pdev)
                ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
                                                 &priv->dir_reg_offset);
                if (ret)
-                       dev_err(dev, "can't read the dir register offset!\n");
+                       dev_dbg(dev, "can't read the dir register offset!\n");
 
                priv->dir_reg_offset <<= 3;
        }
index 472fb5b..9cdbc0c 100644 (file)
@@ -26,9 +26,12 @@ struct tps65912_gpio_data {
        struct gpio_chip gpio_chip;
 };
 
+#define to_tgd(gc) container_of(gc, struct tps65912_gpio_data, gpio_chip)
+
 static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
        int val;
 
        val = tps65912_reg_read(tps65912, TPS65912_GPIO1 + offset);
@@ -42,7 +45,8 @@ static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
 static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
                              int value)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        if (value)
                tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
@@ -55,7 +59,8 @@ static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
 static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
                                int value)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        /* Set the initial value */
        tps65912_gpio_set(gc, offset, value);
@@ -66,7 +71,8 @@ static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
 
 static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
                                                                GPIO_CFG_MASK);
index c0929d9..df990f2 100644 (file)
@@ -201,6 +201,10 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
        if (!handler)
                return AE_BAD_PARAMETER;
 
+       pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+       if (pin < 0)
+               return AE_BAD_PARAMETER;
+
        desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
        if (IS_ERR(desc)) {
                dev_err(chip->dev, "Failed to request GPIO\n");
@@ -551,6 +555,12 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                struct gpio_desc *desc;
                bool found;
 
+               pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+               if (pin < 0) {
+                       status = AE_BAD_PARAMETER;
+                       goto out;
+               }
+
                mutex_lock(&achip->conn_lock);
 
                found = false;
index 8cad8e4..4650bf8 100644 (file)
@@ -46,12 +46,13 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
 
        ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
        if (ret < 0) {
-               /* We've found the gpio chip, but the translation failed.
-                * Return true to stop looking and return the translation
-                * error via out_gpio
+               /* We've found a gpio chip, but the translation failed.
+                * Store translation error in out_gpio.
+                * Return false to keep looking, as more than one gpio chip
+                * could be registered per of-node.
                 */
                gg_data->out_gpio = ERR_PTR(ret);
-               return true;
+               return false;
         }
 
        gg_data->out_gpio = gpiochip_get_desc(gc, ret);
index b3589d0..d8135ad 100644 (file)
@@ -62,12 +62,18 @@ enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type)
        return KFD_MQD_TYPE_CP;
 }
 
-static inline unsigned int get_first_pipe(struct device_queue_manager *dqm)
+unsigned int get_first_pipe(struct device_queue_manager *dqm)
 {
-       BUG_ON(!dqm);
+       BUG_ON(!dqm || !dqm->dev);
        return dqm->dev->shared_resources.first_compute_pipe;
 }
 
+unsigned int get_pipes_num(struct device_queue_manager *dqm)
+{
+       BUG_ON(!dqm || !dqm->dev);
+       return dqm->dev->shared_resources.compute_pipe_count;
+}
+
 static inline unsigned int get_pipes_num_cpsch(void)
 {
        return PIPE_PER_ME_CP_SCHEDULING;
@@ -639,6 +645,7 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
        pr_debug("     sdma queue id: %d\n", q->properties.sdma_queue_id);
        pr_debug("     sdma engine id: %d\n", q->properties.sdma_engine_id);
 
+       init_sdma_vm(dqm, q, qpd);
        retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
                                &q->gart_mqd_addr, &q->properties);
        if (retval != 0) {
@@ -646,7 +653,14 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
                return retval;
        }
 
-       init_sdma_vm(dqm, q, qpd);
+       retval = mqd->load_mqd(mqd, q->mqd, 0,
+                               0, NULL);
+       if (retval != 0) {
+               deallocate_sdma_queue(dqm, q->sdma_id);
+               mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
+               return retval;
+       }
+
        return 0;
 }
 
index d64f86c..488f51d 100644 (file)
@@ -163,6 +163,8 @@ void program_sh_mem_settings(struct device_queue_manager *dqm,
                                        struct qcm_process_device *qpd);
 int init_pipelines(struct device_queue_manager *dqm,
                unsigned int pipes_num, unsigned int first_pipe);
+unsigned int get_first_pipe(struct device_queue_manager *dqm);
+unsigned int get_pipes_num(struct device_queue_manager *dqm);
 
 extern inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
 {
@@ -175,10 +177,4 @@ get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
        return (pdd->lds_base >> 60) & 0x0E;
 }
 
-extern inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
-{
-       BUG_ON(!dqm || !dqm->dev);
-       return dqm->dev->shared_resources.compute_pipe_count;
-}
-
 #endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */
index 6b07246..5469efe 100644 (file)
@@ -131,5 +131,5 @@ static int register_process_cik(struct device_queue_manager *dqm,
 
 static int initialize_cpsch_cik(struct device_queue_manager *dqm)
 {
-       return init_pipelines(dqm, get_pipes_num(dqm), 0);
+       return init_pipelines(dqm, get_pipes_num(dqm), get_first_pipe(dqm));
 }
index e415a2a..c7d298e 100644 (file)
@@ -44,7 +44,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
        BUG_ON(!kq || !dev);
        BUG_ON(type != KFD_QUEUE_TYPE_DIQ && type != KFD_QUEUE_TYPE_HIQ);
 
-       pr_debug("kfd: In func %s initializing queue type %d size %d\n",
+       pr_debug("amdkfd: In func %s initializing queue type %d size %d\n",
                        __func__, KFD_QUEUE_TYPE_HIQ, queue_size);
 
        nop.opcode = IT_NOP;
@@ -69,12 +69,16 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
 
        prop.doorbell_ptr = kfd_get_kernel_doorbell(dev, &prop.doorbell_off);
 
-       if (prop.doorbell_ptr == NULL)
+       if (prop.doorbell_ptr == NULL) {
+               pr_err("amdkfd: error init doorbell");
                goto err_get_kernel_doorbell;
+       }
 
        retval = kfd_gtt_sa_allocate(dev, queue_size, &kq->pq);
-       if (retval != 0)
+       if (retval != 0) {
+               pr_err("amdkfd: error init pq queues size (%d)\n", queue_size);
                goto err_pq_allocate_vidmem;
+       }
 
        kq->pq_kernel_addr = kq->pq->cpu_ptr;
        kq->pq_gpu_addr = kq->pq->gpu_addr;
@@ -165,10 +169,8 @@ err_rptr_allocate_vidmem:
 err_eop_allocate_vidmem:
        kfd_gtt_sa_free(dev, kq->pq);
 err_pq_allocate_vidmem:
-       pr_err("kfd: error init pq\n");
        kfd_release_kernel_doorbell(dev, prop.doorbell_ptr);
 err_get_kernel_doorbell:
-       pr_err("kfd: error init doorbell");
        return false;
 
 }
@@ -187,6 +189,8 @@ static void uninitialize(struct kernel_queue *kq)
        else if (kq->queue->properties.type == KFD_QUEUE_TYPE_DIQ)
                kfd_gtt_sa_free(kq->dev, kq->fence_mem_obj);
 
+       kq->mqd->uninit_mqd(kq->mqd, kq->queue->mqd, kq->queue->mqd_mem_obj);
+
        kfd_gtt_sa_free(kq->dev, kq->rptr_mem);
        kfd_gtt_sa_free(kq->dev, kq->wptr_mem);
        kq->ops_asic_specific.uninitialize(kq);
@@ -211,7 +215,7 @@ static int acquire_packet_buffer(struct kernel_queue *kq,
        queue_address = (unsigned int *)kq->pq_kernel_addr;
        queue_size_dwords = kq->queue->properties.queue_size / sizeof(uint32_t);
 
-       pr_debug("kfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
+       pr_debug("amdkfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
                        __func__, rptr, wptr, queue_address);
 
        available_size = (rptr - 1 - wptr + queue_size_dwords) %
@@ -296,7 +300,7 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
        }
 
        if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
-               pr_err("kfd: failed to init kernel queue\n");
+               pr_err("amdkfd: failed to init kernel queue\n");
                kfree(kq);
                return NULL;
        }
@@ -319,7 +323,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
 
        BUG_ON(!dev);
 
-       pr_err("kfd: starting kernel queue test\n");
+       pr_err("amdkfd: starting kernel queue test\n");
 
        kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ);
        BUG_ON(!kq);
@@ -330,7 +334,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
                buffer[i] = kq->nop_packet;
        kq->ops.submit_packet(kq);
 
-       pr_err("kfd: ending kernel queue test\n");
+       pr_err("amdkfd: ending kernel queue test\n");
 }
 
 
index 0409b90..b3e3068 100644 (file)
@@ -153,7 +153,7 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
                     (adj->crtc_hdisplay - 1) |
                     ((adj->crtc_vdisplay - 1) << 16));
 
-       cfg = ATMEL_HLCDC_CLKPOL;
+       cfg = 0;
 
        prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
        mode_rate = mode->crtc_clock * 1000;
index 7320a6c..c1cb174 100644 (file)
@@ -311,8 +311,6 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
 
        pm_runtime_enable(dev->dev);
 
-       pm_runtime_put_sync(dev->dev);
-
        ret = atmel_hlcdc_dc_modeset_init(dev);
        if (ret < 0) {
                dev_err(dev->dev, "failed to initialize mode setting\n");
index 063d2a7..e79bd9b 100644 (file)
@@ -311,7 +311,8 @@ int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
 
        /* Disable the layer */
        regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
-                    ATMEL_HLCDC_LAYER_RST);
+                    ATMEL_HLCDC_LAYER_RST | ATMEL_HLCDC_LAYER_A2Q |
+                    ATMEL_HLCDC_LAYER_UPDATE);
 
        /* Clear all pending interrupts */
        regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
index 6b00173..679b10e 100644 (file)
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
-static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
-                                                       struct drm_mode_fb_cmd2 *r,
-                                                       struct drm_file *file_priv);
+static struct drm_framebuffer *
+internal_framebuffer_create(struct drm_device *dev,
+                           struct drm_mode_fb_cmd2 *r,
+                           struct drm_file *file_priv);
 
 /* Avoid boilerplate.  I'm tired of typing. */
 #define DRM_ENUM_NAME_FN(fnname, list)                         \
@@ -524,17 +525,6 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb)
 }
 EXPORT_SYMBOL(drm_framebuffer_reference);
 
-static void drm_framebuffer_free_bug(struct kref *kref)
-{
-       BUG();
-}
-
-static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
-{
-       DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount));
-       kref_put(&fb->refcount, drm_framebuffer_free_bug);
-}
-
 /**
  * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
  * @fb: fb to unregister
@@ -1319,7 +1309,7 @@ void drm_plane_force_disable(struct drm_plane *plane)
                return;
        }
        /* disconnect the plane from the fb and crtc: */
-       __drm_framebuffer_unreference(plane->old_fb);
+       drm_framebuffer_unreference(plane->old_fb);
        plane->old_fb = NULL;
        plane->fb = NULL;
        plane->crtc = NULL;
@@ -2127,7 +2117,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
 
        mutex_lock(&dev->mode_config.mutex);
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 
        connector = drm_connector_find(dev, out_resp->connector_id);
        if (!connector) {
@@ -2157,6 +2146,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        out_resp->mm_height = connector->display_info.height_mm;
        out_resp->subpixel = connector->display_info.subpixel_order;
        out_resp->connection = connector->status;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
        encoder = drm_connector_get_encoder(connector);
        if (encoder)
                out_resp->encoder_id = encoder->base.id;
@@ -2907,13 +2898,11 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
         */
        if (req->flags & DRM_MODE_CURSOR_BO) {
                if (req->handle) {
-                       fb = add_framebuffer_internal(dev, &fbreq, file_priv);
+                       fb = internal_framebuffer_create(dev, &fbreq, file_priv);
                        if (IS_ERR(fb)) {
                                DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
                                return PTR_ERR(fb);
                        }
-
-                       drm_framebuffer_reference(fb);
                } else {
                        fb = NULL;
                }
@@ -3266,9 +3255,10 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
        return 0;
 }
 
-static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
-                                                       struct drm_mode_fb_cmd2 *r,
-                                                       struct drm_file *file_priv)
+static struct drm_framebuffer *
+internal_framebuffer_create(struct drm_device *dev,
+                           struct drm_mode_fb_cmd2 *r,
+                           struct drm_file *file_priv)
 {
        struct drm_mode_config *config = &dev->mode_config;
        struct drm_framebuffer *fb;
@@ -3300,12 +3290,6 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
                return fb;
        }
 
-       mutex_lock(&file_priv->fbs_lock);
-       r->fb_id = fb->base.id;
-       list_add(&fb->filp_head, &file_priv->fbs);
-       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
-       mutex_unlock(&file_priv->fbs_lock);
-
        return fb;
 }
 
@@ -3327,15 +3311,24 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
 int drm_mode_addfb2(struct drm_device *dev,
                    void *data, struct drm_file *file_priv)
 {
+       struct drm_mode_fb_cmd2 *r = data;
        struct drm_framebuffer *fb;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       fb = add_framebuffer_internal(dev, data, file_priv);
+       fb = internal_framebuffer_create(dev, r, file_priv);
        if (IS_ERR(fb))
                return PTR_ERR(fb);
 
+       /* Transfer ownership to the filp for reaping on close */
+
+       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
+       mutex_lock(&file_priv->fbs_lock);
+       r->fb_id = fb->base.id;
+       list_add(&fb->filp_head, &file_priv->fbs);
+       mutex_unlock(&file_priv->fbs_lock);
+
        return 0;
 }
 
index 9a5b687..379ab45 100644 (file)
@@ -733,10 +733,14 @@ static bool check_txmsg_state(struct drm_dp_mst_topology_mgr *mgr,
                              struct drm_dp_sideband_msg_tx *txmsg)
 {
        bool ret;
-       mutex_lock(&mgr->qlock);
+
+       /*
+        * All updates to txmsg->state are protected by mgr->qlock, and the two
+        * cases we check here are terminal states. For those the barriers
+        * provided by the wake_up/wait_event pair are enough.
+        */
        ret = (txmsg->state == DRM_DP_SIDEBAND_TX_RX ||
               txmsg->state == DRM_DP_SIDEBAND_TX_TIMEOUT);
-       mutex_unlock(&mgr->qlock);
        return ret;
 }
 
@@ -1363,12 +1367,13 @@ static int process_single_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
        return 0;
 }
 
-/* must be called holding qlock */
 static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr)
 {
        struct drm_dp_sideband_msg_tx *txmsg;
        int ret;
 
+       WARN_ON(!mutex_is_locked(&mgr->qlock));
+
        /* construct a chunk from the first msg in the tx_msg queue */
        if (list_empty(&mgr->tx_msg_downq)) {
                mgr->tx_down_in_progress = false;
index 732cb6f..4c0aa97 100644 (file)
@@ -287,6 +287,7 @@ int drm_load_edid_firmware(struct drm_connector *connector)
 
        drm_mode_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
+       drm_edid_to_eld(connector, edid);
        kfree(edid);
 
        return ret;
index 04a209e..1134526 100644 (file)
  */
 
 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
-                                               unsigned long size,
+                                               u64 size,
                                                unsigned alignment,
                                                unsigned long color,
                                                enum drm_mm_search_flags flags);
 static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
-                                               unsigned long size,
+                                               u64 size,
                                                unsigned alignment,
                                                unsigned long color,
-                                               unsigned long start,
-                                               unsigned long end,
+                                               u64 start,
+                                               u64 end,
                                                enum drm_mm_search_flags flags);
 
 static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
                                 struct drm_mm_node *node,
-                                unsigned long size, unsigned alignment,
+                                u64 size, unsigned alignment,
                                 unsigned long color,
                                 enum drm_mm_allocator_flags flags)
 {
        struct drm_mm *mm = hole_node->mm;
-       unsigned long hole_start = drm_mm_hole_node_start(hole_node);
-       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
-       unsigned long adj_start = hole_start;
-       unsigned long adj_end = hole_end;
+       u64 hole_start = drm_mm_hole_node_start(hole_node);
+       u64 hole_end = drm_mm_hole_node_end(hole_node);
+       u64 adj_start = hole_start;
+       u64 adj_end = hole_end;
 
        BUG_ON(node->allocated);
 
@@ -124,12 +124,15 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
                adj_start = adj_end - size;
 
        if (alignment) {
-               unsigned tmp = adj_start % alignment;
-               if (tmp) {
+               u64 tmp = adj_start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem) {
                        if (flags & DRM_MM_CREATE_TOP)
-                               adj_start -= tmp;
+                               adj_start -= rem;
                        else
-                               adj_start += alignment - tmp;
+                               adj_start += alignment - rem;
                }
        }
 
@@ -176,9 +179,9 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
 int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
 {
        struct drm_mm_node *hole;
-       unsigned long end = node->start + node->size;
-       unsigned long hole_start;
-       unsigned long hole_end;
+       u64 end = node->start + node->size;
+       u64 hole_start;
+       u64 hole_end;
 
        BUG_ON(node == NULL);
 
@@ -227,7 +230,7 @@ EXPORT_SYMBOL(drm_mm_reserve_node);
  * 0 on success, -ENOSPC if there's no suitable hole.
  */
 int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
-                              unsigned long size, unsigned alignment,
+                              u64 size, unsigned alignment,
                               unsigned long color,
                               enum drm_mm_search_flags sflags,
                               enum drm_mm_allocator_flags aflags)
@@ -246,16 +249,16 @@ EXPORT_SYMBOL(drm_mm_insert_node_generic);
 
 static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
                                       struct drm_mm_node *node,
-                                      unsigned long size, unsigned alignment,
+                                      u64 size, unsigned alignment,
                                       unsigned long color,
-                                      unsigned long start, unsigned long end,
+                                      u64 start, u64 end,
                                       enum drm_mm_allocator_flags flags)
 {
        struct drm_mm *mm = hole_node->mm;
-       unsigned long hole_start = drm_mm_hole_node_start(hole_node);
-       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
-       unsigned long adj_start = hole_start;
-       unsigned long adj_end = hole_end;
+       u64 hole_start = drm_mm_hole_node_start(hole_node);
+       u64 hole_end = drm_mm_hole_node_end(hole_node);
+       u64 adj_start = hole_start;
+       u64 adj_end = hole_end;
 
        BUG_ON(!hole_node->hole_follows || node->allocated);
 
@@ -271,12 +274,15 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
                mm->color_adjust(hole_node, color, &adj_start, &adj_end);
 
        if (alignment) {
-               unsigned tmp = adj_start % alignment;
-               if (tmp) {
+               u64 tmp = adj_start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem) {
                        if (flags & DRM_MM_CREATE_TOP)
-                               adj_start -= tmp;
+                               adj_start -= rem;
                        else
-                               adj_start += alignment - tmp;
+                               adj_start += alignment - rem;
                }
        }
 
@@ -324,9 +330,9 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
  * 0 on success, -ENOSPC if there's no suitable hole.
  */
 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
-                                       unsigned long size, unsigned alignment,
+                                       u64 size, unsigned alignment,
                                        unsigned long color,
-                                       unsigned long start, unsigned long end,
+                                       u64 start, u64 end,
                                        enum drm_mm_search_flags sflags,
                                        enum drm_mm_allocator_flags aflags)
 {
@@ -387,32 +393,34 @@ void drm_mm_remove_node(struct drm_mm_node *node)
 }
 EXPORT_SYMBOL(drm_mm_remove_node);
 
-static int check_free_hole(unsigned long start, unsigned long end,
-                          unsigned long size, unsigned alignment)
+static int check_free_hole(u64 start, u64 end, u64 size, unsigned alignment)
 {
        if (end - start < size)
                return 0;
 
        if (alignment) {
-               unsigned tmp = start % alignment;
-               if (tmp)
-                       start += alignment - tmp;
+               u64 tmp = start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem)
+                       start += alignment - rem;
        }
 
        return end >= start + size;
 }
 
 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
-                                                     unsigned long size,
+                                                     u64 size,
                                                      unsigned alignment,
                                                      unsigned long color,
                                                      enum drm_mm_search_flags flags)
 {
        struct drm_mm_node *entry;
        struct drm_mm_node *best;
-       unsigned long adj_start;
-       unsigned long adj_end;
-       unsigned long best_size;
+       u64 adj_start;
+       u64 adj_end;
+       u64 best_size;
 
        BUG_ON(mm->scanned_blocks);
 
@@ -421,7 +429,7 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
 
        __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
                               flags & DRM_MM_SEARCH_BELOW) {
-               unsigned long hole_size = adj_end - adj_start;
+               u64 hole_size = adj_end - adj_start;
 
                if (mm->color_adjust) {
                        mm->color_adjust(entry, color, &adj_start, &adj_end);
@@ -445,18 +453,18 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
 }
 
 static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
-                                                       unsigned long size,
+                                                       u64 size,
                                                        unsigned alignment,
                                                        unsigned long color,
-                                                       unsigned long start,
-                                                       unsigned long end,
+                                                       u64 start,
+                                                       u64 end,
                                                        enum drm_mm_search_flags flags)
 {
        struct drm_mm_node *entry;
        struct drm_mm_node *best;
-       unsigned long adj_start;
-       unsigned long adj_end;
-       unsigned long best_size;
+       u64 adj_start;
+       u64 adj_end;
+       u64 best_size;
 
        BUG_ON(mm->scanned_blocks);
 
@@ -465,7 +473,7 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
 
        __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
                               flags & DRM_MM_SEARCH_BELOW) {
-               unsigned long hole_size = adj_end - adj_start;
+               u64 hole_size = adj_end - adj_start;
 
                if (adj_start < start)
                        adj_start = start;
@@ -561,7 +569,7 @@ EXPORT_SYMBOL(drm_mm_replace_node);
  * adding/removing nodes to/from the scan list are allowed.
  */
 void drm_mm_init_scan(struct drm_mm *mm,
-                     unsigned long size,
+                     u64 size,
                      unsigned alignment,
                      unsigned long color)
 {
@@ -594,11 +602,11 @@ EXPORT_SYMBOL(drm_mm_init_scan);
  * adding/removing nodes to/from the scan list are allowed.
  */
 void drm_mm_init_scan_with_range(struct drm_mm *mm,
-                                unsigned long size,
+                                u64 size,
                                 unsigned alignment,
                                 unsigned long color,
-                                unsigned long start,
-                                unsigned long end)
+                                u64 start,
+                                u64 end)
 {
        mm->scan_color = color;
        mm->scan_alignment = alignment;
@@ -627,8 +635,8 @@ bool drm_mm_scan_add_block(struct drm_mm_node *node)
 {
        struct drm_mm *mm = node->mm;
        struct drm_mm_node *prev_node;
-       unsigned long hole_start, hole_end;
-       unsigned long adj_start, adj_end;
+       u64 hole_start, hole_end;
+       u64 adj_start, adj_end;
 
        mm->scanned_blocks++;
 
@@ -731,7 +739,7 @@ EXPORT_SYMBOL(drm_mm_clean);
  *
  * Note that @mm must be cleared to 0 before calling this function.
  */
-void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
+void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
 {
        INIT_LIST_HEAD(&mm->hole_stack);
        mm->scanned_blocks = 0;
@@ -766,18 +774,17 @@ void drm_mm_takedown(struct drm_mm * mm)
 }
 EXPORT_SYMBOL(drm_mm_takedown);
 
-static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
-                                      const char *prefix)
+static u64 drm_mm_debug_hole(struct drm_mm_node *entry,
+                                    const char *prefix)
 {
-       unsigned long hole_start, hole_end, hole_size;
+       u64 hole_start, hole_end, hole_size;
 
        if (entry->hole_follows) {
                hole_start = drm_mm_hole_node_start(entry);
                hole_end = drm_mm_hole_node_end(entry);
                hole_size = hole_end - hole_start;
-               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
-                       prefix, hole_start, hole_end,
-                       hole_size);
+               pr_debug("%s %#llx-%#llx: %llu: free\n", prefix, hole_start,
+                        hole_end, hole_size);
                return hole_size;
        }
 
@@ -792,35 +799,34 @@ static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
 void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
 {
        struct drm_mm_node *entry;
-       unsigned long total_used = 0, total_free = 0, total = 0;
+       u64 total_used = 0, total_free = 0, total = 0;
 
        total_free += drm_mm_debug_hole(&mm->head_node, prefix);
 
        drm_mm_for_each_node(entry, mm) {
-               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
-                       prefix, entry->start, entry->start + entry->size,
-                       entry->size);
+               pr_debug("%s %#llx-%#llx: %llu: used\n", prefix, entry->start,
+                        entry->start + entry->size, entry->size);
                total_used += entry->size;
                total_free += drm_mm_debug_hole(entry, prefix);
        }
        total = total_free + total_used;
 
-       printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total,
-               total_used, total_free);
+       pr_debug("%s total: %llu, used %llu free %llu\n", prefix, total,
+                total_used, total_free);
 }
 EXPORT_SYMBOL(drm_mm_debug_table);
 
 #if defined(CONFIG_DEBUG_FS)
-static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
+static u64 drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
 {
-       unsigned long hole_start, hole_end, hole_size;
+       u64 hole_start, hole_end, hole_size;
 
        if (entry->hole_follows) {
                hole_start = drm_mm_hole_node_start(entry);
                hole_end = drm_mm_hole_node_end(entry);
                hole_size = hole_end - hole_start;
-               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
-                               hole_start, hole_end, hole_size);
+               seq_printf(m, "%#llx-%#llx: %llu: free\n", hole_start,
+                          hole_end, hole_size);
                return hole_size;
        }
 
@@ -835,20 +841,20 @@ static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *en
 int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
 {
        struct drm_mm_node *entry;
-       unsigned long total_used = 0, total_free = 0, total = 0;
+       u64 total_used = 0, total_free = 0, total = 0;
 
        total_free += drm_mm_dump_hole(m, &mm->head_node);
 
        drm_mm_for_each_node(entry, mm) {
-               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
-                               entry->start, entry->start + entry->size,
-                               entry->size);
+               seq_printf(m, "%#016llx-%#016llx: %llu: used\n", entry->start,
+                          entry->start + entry->size, entry->size);
                total_used += entry->size;
                total_free += drm_mm_dump_hole(m, entry);
        }
        total = total_free + total_used;
 
-       seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free);
+       seq_printf(m, "total: %llu, used %llu free %llu\n", total,
+                  total_used, total_free);
        return 0;
 }
 EXPORT_SYMBOL(drm_mm_dump_table);
index 6591d48..3fee587 100644 (file)
@@ -174,6 +174,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
                        struct edid *edid = (struct edid *) connector->edid_blob_ptr->data;
 
                        count = drm_add_edid_modes(connector, edid);
+                       drm_edid_to_eld(connector, edid);
                } else
                        count = (*connector_funcs->get_modes)(connector);
        }
index a5e7461..0a67803 100644 (file)
@@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI
 
 config DRM_EXYNOS_DP
        bool "EXYNOS DRM DP driver support"
-       depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
+       depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
        default DRM_EXYNOS
        select DRM_PANEL
        help
index 63f02e2..9700461 100644 (file)
@@ -888,8 +888,8 @@ static int decon_probe(struct platform_device *pdev)
        of_node_put(i80_if_timings);
 
        ctx->regs = of_iomap(dev->of_node, 0);
-       if (IS_ERR(ctx->regs)) {
-               ret = PTR_ERR(ctx->regs);
+       if (!ctx->regs) {
+               ret = -ENOMEM;
                goto err_del_component;
        }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
deleted file mode 100644 (file)
index ba9b3d5..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Joonyoung Shim <jy0922.shim@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-
-#include <drm/exynos_drm.h>
-#include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
-#include "exynos_drm_connector.h"
-
-#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
-                               drm_connector)
-
-struct exynos_drm_connector {
-       struct drm_connector            drm_connector;
-       uint32_t                        encoder_id;
-       struct exynos_drm_display       *display;
-};
-
-static int exynos_drm_connector_get_modes(struct drm_connector *connector)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       struct edid *edid = NULL;
-       unsigned int count = 0;
-       int ret;
-
-       /*
-        * if get_edid() exists then get_edid() callback of hdmi side
-        * is called to get edid data through i2c interface else
-        * get timing from the FIMD driver(display controller).
-        *
-        * P.S. in case of lcd panel, count is always 1 if success
-        * because lcd panel has only one mode.
-        */
-       if (display->ops->get_edid) {
-               edid = display->ops->get_edid(display, connector);
-               if (IS_ERR_OR_NULL(edid)) {
-                       ret = PTR_ERR(edid);
-                       edid = NULL;
-                       DRM_ERROR("Panel operation get_edid failed %d\n", ret);
-                       goto out;
-               }
-
-               count = drm_add_edid_modes(connector, edid);
-               if (!count) {
-                       DRM_ERROR("Add edid modes failed %d\n", count);
-                       goto out;
-               }
-
-               drm_mode_connector_update_edid_property(connector, edid);
-       } else {
-               struct exynos_drm_panel_info *panel;
-               struct drm_display_mode *mode = drm_mode_create(connector->dev);
-               if (!mode) {
-                       DRM_ERROR("failed to create a new display mode.\n");
-                       return 0;
-               }
-
-               if (display->ops->get_panel)
-                       panel = display->ops->get_panel(display);
-               else {
-                       drm_mode_destroy(connector->dev, mode);
-                       return 0;
-               }
-
-               drm_display_mode_from_videomode(&panel->vm, mode);
-               mode->width_mm = panel->width_mm;
-               mode->height_mm = panel->height_mm;
-               connector->display_info.width_mm = mode->width_mm;
-               connector->display_info.height_mm = mode->height_mm;
-
-               mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-               drm_mode_set_name(mode);
-               drm_mode_probed_add(connector, mode);
-
-               count = 1;
-       }
-
-out:
-       kfree(edid);
-       return count;
-}
-
-static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
-                                           struct drm_display_mode *mode)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       int ret = MODE_BAD;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (display->ops->check_mode)
-               if (!display->ops->check_mode(display, mode))
-                       ret = MODE_OK;
-
-       return ret;
-}
-
-static struct drm_encoder *exynos_drm_best_encoder(
-               struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       return drm_encoder_find(dev, exynos_connector->encoder_id);
-}
-
-static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
-       .get_modes      = exynos_drm_connector_get_modes,
-       .mode_valid     = exynos_drm_connector_mode_valid,
-       .best_encoder   = exynos_drm_best_encoder,
-};
-
-static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
-                               unsigned int max_width, unsigned int max_height)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       unsigned int width, height;
-
-       width = max_width;
-       height = max_height;
-
-       /*
-        * if specific driver want to find desired_mode using maxmum
-        * resolution then get max width and height from that driver.
-        */
-       if (display->ops->get_max_resol)
-               display->ops->get_max_resol(display, &width, &height);
-
-       return drm_helper_probe_single_connector_modes(connector, width,
-                                                       height);
-}
-
-/* get detection status of display device. */
-static enum drm_connector_status
-exynos_drm_connector_detect(struct drm_connector *connector, bool force)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       enum drm_connector_status status = connector_status_disconnected;
-
-       if (display->ops->is_connected) {
-               if (display->ops->is_connected(display))
-                       status = connector_status_connected;
-               else
-                       status = connector_status_disconnected;
-       }
-
-       return status;
-}
-
-static void exynos_drm_connector_destroy(struct drm_connector *connector)
-{
-       struct exynos_drm_connector *exynos_connector =
-               to_exynos_connector(connector);
-
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-       kfree(exynos_connector);
-}
-
-static struct drm_connector_funcs exynos_connector_funcs = {
-       .dpms           = drm_helper_connector_dpms,
-       .fill_modes     = exynos_drm_connector_fill_modes,
-       .detect         = exynos_drm_connector_detect,
-       .destroy        = exynos_drm_connector_destroy,
-};
-
-struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
-                                                  struct drm_encoder *encoder)
-{
-       struct exynos_drm_connector *exynos_connector;
-       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
-       struct drm_connector *connector;
-       int type;
-       int err;
-
-       exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
-       if (!exynos_connector)
-               return NULL;
-
-       connector = &exynos_connector->drm_connector;
-
-       switch (display->type) {
-       case EXYNOS_DISPLAY_TYPE_HDMI:
-               type = DRM_MODE_CONNECTOR_HDMIA;
-               connector->interlace_allowed = true;
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-               break;
-       case EXYNOS_DISPLAY_TYPE_VIDI:
-               type = DRM_MODE_CONNECTOR_VIRTUAL;
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-               break;
-       default:
-               type = DRM_MODE_CONNECTOR_Unknown;
-               break;
-       }
-
-       drm_connector_init(dev, connector, &exynos_connector_funcs, type);
-       drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
-
-       err = drm_connector_register(connector);
-       if (err)
-               goto err_connector;
-
-       exynos_connector->encoder_id = encoder->base.id;
-       exynos_connector->display = display;
-       connector->dpms = DRM_MODE_DPMS_OFF;
-       connector->encoder = encoder;
-
-       err = drm_mode_connector_attach_encoder(connector, encoder);
-       if (err) {
-               DRM_ERROR("failed to attach a connector to a encoder\n");
-               goto err_sysfs;
-       }
-
-       DRM_DEBUG_KMS("connector has been created\n");
-
-       return connector;
-
-err_sysfs:
-       drm_connector_unregister(connector);
-err_connector:
-       drm_connector_cleanup(connector);
-       kfree(exynos_connector);
-       return NULL;
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h
deleted file mode 100644 (file)
index 4eb20d7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Joonyoung Shim <jy0922.shim@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_CONNECTOR_H_
-#define _EXYNOS_DRM_CONNECTOR_H_
-
-struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
-                                                  struct drm_encoder *encoder);
-
-#endif
index 925fc69..33a10ce 100644 (file)
@@ -147,6 +147,7 @@ struct fimd_win_data {
        unsigned int            ovl_height;
        unsigned int            fb_width;
        unsigned int            fb_height;
+       unsigned int            fb_pitch;
        unsigned int            bpp;
        unsigned int            pixel_format;
        dma_addr_t              dma_addr;
@@ -284,14 +285,9 @@ static void fimd_clear_channel(struct fimd_context *ctx)
        }
 }
 
-static int fimd_ctx_initialize(struct fimd_context *ctx,
+static int fimd_iommu_attach_devices(struct fimd_context *ctx,
                        struct drm_device *drm_dev)
 {
-       struct exynos_drm_private *priv;
-       priv = drm_dev->dev_private;
-
-       ctx->drm_dev = drm_dev;
-       ctx->pipe = priv->pipe++;
 
        /* attach this sub driver to iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev)) {
@@ -313,7 +309,7 @@ static int fimd_ctx_initialize(struct fimd_context *ctx,
        return 0;
 }
 
-static void fimd_ctx_remove(struct fimd_context *ctx)
+static void fimd_iommu_detach_devices(struct fimd_context *ctx)
 {
        /* detach this sub driver from iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev))
@@ -537,13 +533,14 @@ static void fimd_win_mode_set(struct exynos_drm_crtc *crtc,
        win_data->offset_y = plane->crtc_y;
        win_data->ovl_width = plane->crtc_width;
        win_data->ovl_height = plane->crtc_height;
+       win_data->fb_pitch = plane->pitch;
        win_data->fb_width = plane->fb_width;
        win_data->fb_height = plane->fb_height;
        win_data->dma_addr = plane->dma_addr[0] + offset;
        win_data->bpp = plane->bpp;
        win_data->pixel_format = plane->pixel_format;
-       win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
-                               (plane->bpp >> 3);
+       win_data->buf_offsize =
+               plane->pitch - (plane->crtc_width * (plane->bpp >> 3));
        win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
 
        DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
@@ -709,7 +706,7 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
 
        /* buffer end address */
-       size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
+       size = win_data->fb_pitch * win_data->ovl_height * (win_data->bpp >> 3);
        val = (unsigned long)(win_data->dma_addr + size);
        writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
 
@@ -1056,25 +1053,23 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
 {
        struct fimd_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_private *priv = drm_dev->dev_private;
        int ret;
 
-       ret = fimd_ctx_initialize(ctx, drm_dev);
-       if (ret) {
-               DRM_ERROR("fimd_ctx_initialize failed.\n");
-               return ret;
-       }
+       ctx->drm_dev = drm_dev;
+       ctx->pipe = priv->pipe++;
 
        ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
                                           EXYNOS_DISPLAY_TYPE_LCD,
                                           &fimd_crtc_ops, ctx);
-       if (IS_ERR(ctx->crtc)) {
-               fimd_ctx_remove(ctx);
-               return PTR_ERR(ctx->crtc);
-       }
 
        if (ctx->display)
                exynos_drm_create_enc_conn(drm_dev, ctx->display);
 
+       ret = fimd_iommu_attach_devices(ctx, drm_dev);
+       if (ret)
+               return ret;
+
        return 0;
 
 }
@@ -1086,10 +1081,10 @@ static void fimd_unbind(struct device *dev, struct device *master,
 
        fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
 
+       fimd_iommu_detach_devices(ctx);
+
        if (ctx->display)
                exynos_dpi_remove(ctx->display);
-
-       fimd_ctx_remove(ctx);
 }
 
 static const struct component_ops fimd_component_ops = {
index a561687..8ad5b72 100644 (file)
@@ -175,7 +175,7 @@ static int exynos_disable_plane(struct drm_plane *plane)
        struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc);
 
-       if (exynos_crtc->ops->win_disable)
+       if (exynos_crtc && exynos_crtc->ops->win_disable)
                exynos_crtc->ops->win_disable(exynos_crtc,
                                              exynos_plane->zpos);
 
index 3518bc4..2e3bc57 100644 (file)
@@ -55,6 +55,7 @@ struct hdmi_win_data {
        unsigned int            fb_x;
        unsigned int            fb_y;
        unsigned int            fb_width;
+       unsigned int            fb_pitch;
        unsigned int            fb_height;
        unsigned int            src_width;
        unsigned int            src_height;
@@ -438,7 +439,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        } else {
                luma_addr[0] = win_data->dma_addr;
                chroma_addr[0] = win_data->dma_addr
-                       + (win_data->fb_width * win_data->fb_height);
+                       + (win_data->fb_pitch * win_data->fb_height);
        }
 
        if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
@@ -447,8 +448,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
                        luma_addr[1] = luma_addr[0] + 0x40;
                        chroma_addr[1] = chroma_addr[0] + 0x40;
                } else {
-                       luma_addr[1] = luma_addr[0] + win_data->fb_width;
-                       chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
+                       luma_addr[1] = luma_addr[0] + win_data->fb_pitch;
+                       chroma_addr[1] = chroma_addr[0] + win_data->fb_pitch;
                }
        } else {
                ctx->interlace = false;
@@ -469,10 +470,10 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
 
        /* setting size of input image */
-       vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
+       vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_pitch) |
                VP_IMG_VSIZE(win_data->fb_height));
        /* chroma height has to reduced by 2 to avoid chroma distorions */
-       vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
+       vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_pitch) |
                VP_IMG_VSIZE(win_data->fb_height / 2));
 
        vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
@@ -559,7 +560,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
        /* converting dma address base and source offset */
        dma_addr = win_data->dma_addr
                + (win_data->fb_x * win_data->bpp >> 3)
-               + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
+               + (win_data->fb_y * win_data->fb_pitch);
        src_x_offset = 0;
        src_y_offset = 0;
 
@@ -576,7 +577,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
                MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
 
        /* setup geometry */
-       mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
+       mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
+                       win_data->fb_pitch / (win_data->bpp >> 3));
 
        /* setup display size */
        if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
@@ -961,6 +963,7 @@ static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
        win_data->fb_y = plane->fb_y;
        win_data->fb_width = plane->fb_width;
        win_data->fb_height = plane->fb_height;
+       win_data->fb_pitch = plane->pitch;
        win_data->src_width = plane->src_width;
        win_data->src_height = plane->src_height;
 
index 96e811f..e8b18e5 100644 (file)
@@ -152,12 +152,12 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                        seq_puts(m, " (pp");
                else
                        seq_puts(m, " (g");
-               seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)",
+               seq_printf(m, "gtt offset: %08llx, size: %08llx, type: %u)",
                           vma->node.start, vma->node.size,
                           vma->ggtt_view.type);
        }
        if (obj->stolen)
-               seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
+               seq_printf(m, " (stolen: %08llx)", obj->stolen->start);
        if (obj->pin_mappable || obj->fault_mappable) {
                char s[3], *t = s;
                if (obj->pin_mappable)
index 8039cec..cc6ea53 100644 (file)
@@ -622,7 +622,7 @@ static int i915_drm_suspend(struct drm_device *dev)
        return 0;
 }
 
-static int i915_drm_suspend_late(struct drm_device *drm_dev)
+static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
 {
        struct drm_i915_private *dev_priv = drm_dev->dev_private;
        int ret;
@@ -636,7 +636,17 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev)
        }
 
        pci_disable_device(drm_dev->pdev);
-       pci_set_power_state(drm_dev->pdev, PCI_D3hot);
+       /*
+        * During hibernation on some GEN4 platforms the BIOS may try to access
+        * the device even though it's already in D3 and hang the machine. So
+        * leave the device in D0 on those platforms and hope the BIOS will
+        * power down the device properly. Platforms where this was seen:
+        * Lenovo Thinkpad X301, X61s
+        */
+       if (!(hibernation &&
+             drm_dev->pdev->subsystem_vendor == PCI_VENDOR_ID_LENOVO &&
+             INTEL_INFO(dev_priv)->gen == 4))
+               pci_set_power_state(drm_dev->pdev, PCI_D3hot);
 
        return 0;
 }
@@ -662,7 +672,7 @@ int i915_suspend_legacy(struct drm_device *dev, pm_message_t state)
        if (error)
                return error;
 
-       return i915_drm_suspend_late(dev);
+       return i915_drm_suspend_late(dev, false);
 }
 
 static int i915_drm_resume(struct drm_device *dev)
@@ -950,7 +960,17 @@ static int i915_pm_suspend_late(struct device *dev)
        if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       return i915_drm_suspend_late(drm_dev);
+       return i915_drm_suspend_late(drm_dev, false);
+}
+
+static int i915_pm_poweroff_late(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_to_i915(dev)->dev;
+
+       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+               return 0;
+
+       return i915_drm_suspend_late(drm_dev, true);
 }
 
 static int i915_pm_resume_early(struct device *dev)
@@ -1520,7 +1540,7 @@ static const struct dev_pm_ops i915_pm_ops = {
        .thaw_early = i915_pm_resume_early,
        .thaw = i915_pm_resume,
        .poweroff = i915_pm_suspend,
-       .poweroff_late = i915_pm_suspend_late,
+       .poweroff_late = i915_pm_poweroff_late,
        .restore_early = i915_pm_resume_early,
        .restore = i915_pm_resume,
 
index f2a825e..8727086 100644 (file)
@@ -2114,6 +2114,9 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
  * number comparisons on buffer last_read|write_seqno. It also allows an
  * emission time to be associated with the request for tracking how far ahead
  * of the GPU the submission is.
+ *
+ * The requests are reference counted, so upon creation they should have an
+ * initial reference taken using kref_init
  */
 struct drm_i915_gem_request {
        struct kref ref;
@@ -2137,7 +2140,16 @@ struct drm_i915_gem_request {
        /** Position in the ringbuffer of the end of the whole request */
        u32 tail;
 
-       /** Context related to this request */
+       /**
+        * Context related to this request
+        * Contexts are refcounted, so when this request is associated with a
+        * context, we must increment the context's refcount, to guarantee that
+        * it persists while any request is linked to it. Requests themselves
+        * are also refcounted, so the request will only be freed when the last
+        * reference to it is dismissed, and the code in
+        * i915_gem_request_free() will then decrement the refcount on the
+        * context.
+        */
        struct intel_context *ctx;
 
        /** Batch buffer related to this request if any */
@@ -2374,6 +2386,7 @@ struct drm_i915_cmd_table {
                                 (INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
 #define IS_BDW_ULT(dev)                (IS_BROADWELL(dev) && \
                                 ((INTEL_DEVID(dev) & 0xf) == 0x6 ||    \
+                                (INTEL_DEVID(dev) & 0xf) == 0xb ||     \
                                 (INTEL_DEVID(dev) & 0xf) == 0xe))
 #define IS_BDW_GT3(dev)                (IS_BROADWELL(dev) && \
                                 (INTEL_DEVID(dev) & 0x00F0) == 0x0020)
index c26d36c..27ea6bd 100644 (file)
@@ -2659,8 +2659,7 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
                if (submit_req->ctx != ring->default_context)
                        intel_lr_context_unpin(ring, submit_req->ctx);
 
-               i915_gem_context_unreference(submit_req->ctx);
-               kfree(submit_req);
+               i915_gem_request_unreference(submit_req);
        }
 
        /*
@@ -2738,24 +2737,11 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
        WARN_ON(i915_verify_lists(ring->dev));
 
-       /* Move any buffers on the active list that are no longer referenced
-        * by the ringbuffer to the flushing/inactive lists as appropriate,
-        * before we free the context associated with the requests.
+       /* Retire requests first as we use it above for the early return.
+        * If we retire requests last, we may use a later seqno and so clear
+        * the requests lists without clearing the active list, leading to
+        * confusion.
         */
-       while (!list_empty(&ring->active_list)) {
-               struct drm_i915_gem_object *obj;
-
-               obj = list_first_entry(&ring->active_list,
-                                     struct drm_i915_gem_object,
-                                     ring_list);
-
-               if (!i915_gem_request_completed(obj->last_read_req, true))
-                       break;
-
-               i915_gem_object_move_to_inactive(obj);
-       }
-
-
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
                struct intel_ringbuffer *ringbuf;
@@ -2790,6 +2776,23 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
                i915_gem_free_request(request);
        }
 
+       /* Move any buffers on the active list that are no longer referenced
+        * by the ringbuffer to the flushing/inactive lists as appropriate,
+        * before we free the context associated with the requests.
+        */
+       while (!list_empty(&ring->active_list)) {
+               struct drm_i915_gem_object *obj;
+
+               obj = list_first_entry(&ring->active_list,
+                                     struct drm_i915_gem_object,
+                                     ring_list);
+
+               if (!i915_gem_request_completed(obj->last_read_req, true))
+                       break;
+
+               i915_gem_object_move_to_inactive(obj);
+       }
+
        if (unlikely(ring->trace_irq_req &&
                     i915_gem_request_completed(ring->trace_irq_req, true))) {
                ring->irq_put(ring);
@@ -2937,9 +2940,9 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        req = obj->last_read_req;
 
        /* Do this after OLR check to make sure we make forward progress polling
-        * on this IOCTL with a timeout <=0 (like busy ioctl)
+        * on this IOCTL with a timeout == 0 (like busy ioctl)
         */
-       if (args->timeout_ns <= 0) {
+       if (args->timeout_ns == 0) {
                ret = -ETIME;
                goto out;
        }
@@ -2949,7 +2952,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        i915_gem_request_reference(req);
        mutex_unlock(&dev->struct_mutex);
 
-       ret = __i915_wait_request(req, reset_counter, true, &args->timeout_ns,
+       ret = __i915_wait_request(req, reset_counter, true,
+                                 args->timeout_ns > 0 ? &args->timeout_ns : NULL,
                                  file->driver_priv);
        mutex_lock(&dev->struct_mutex);
        i915_gem_request_unreference(req);
@@ -4793,6 +4797,9 @@ i915_gem_init_hw(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
                return -EIO;
 
+       /* Double layer security blanket, see i915_gem_init() */
+       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
        if (dev_priv->ellc_size)
                I915_WRITE(HSW_IDICR, I915_READ(HSW_IDICR) | IDIHASHMSK(0xf));
 
@@ -4825,7 +4832,7 @@ i915_gem_init_hw(struct drm_device *dev)
        for_each_ring(ring, dev_priv, i) {
                ret = ring->init_hw(ring);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        for (i = 0; i < NUM_L3_SLICES(dev); i++)
@@ -4842,9 +4849,11 @@ i915_gem_init_hw(struct drm_device *dev)
                DRM_ERROR("Context enable failed %d\n", ret);
                i915_gem_cleanup_ringbuffer(dev);
 
-               return ret;
+               goto out;
        }
 
+out:
+       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
        return ret;
 }
 
@@ -4878,6 +4887,14 @@ int i915_gem_init(struct drm_device *dev)
                dev_priv->gt.stop_ring = intel_logical_ring_stop;
        }
 
+       /* This is just a security blanket to placate dragons.
+        * On some systems, we very sporadically observe that the first TLBs
+        * used by the CS may be stale, despite us poking the TLB reset. If
+        * we hold the forcewake during initialisation these problems
+        * just magically go away.
+        */
+       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
        ret = i915_gem_init_userptr(dev);
        if (ret)
                goto out_unlock;
@@ -4904,6 +4921,7 @@ int i915_gem_init(struct drm_device *dev)
        }
 
 out_unlock:
+       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
        mutex_unlock(&dev->struct_mutex);
 
        return ret;
index b773368..38a7425 100644 (file)
@@ -1487,7 +1487,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto err;
        }
 
-       if (i915_needs_cmd_parser(ring)) {
+       if (i915_needs_cmd_parser(ring) && args->batch_len) {
                batch_obj = i915_gem_execbuffer_parse(ring,
                                                      &shadow_exec_entry,
                                                      eb,
index 746f77f..dccdc8a 100644 (file)
@@ -1145,7 +1145,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 
        ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);
 
-       DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n",
+       DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n",
                         ppgtt->node.size >> 20,
                         ppgtt->node.start / PAGE_SIZE);
 
@@ -1713,8 +1713,8 @@ void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
 
 static void i915_gtt_color_adjust(struct drm_mm_node *node,
                                  unsigned long color,
-                                 unsigned long *start,
-                                 unsigned long *end)
+                                 u64 *start,
+                                 u64 *end)
 {
        if (node->color != color)
                *start += 4096;
index a204584..9c6f93e 100644 (file)
@@ -485,10 +485,8 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
                        stolen_offset, gtt_offset, size);
 
        /* KISS and expect everything to be page-aligned */
-       BUG_ON(stolen_offset & 4095);
-       BUG_ON(size & 4095);
-
-       if (WARN_ON(size == 0))
+       if (WARN_ON(size == 0) || WARN_ON(size & 4095) ||
+           WARN_ON(stolen_offset & 4095))
                return NULL;
 
        stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
index 7a24bd1..6377b22 100644 (file)
@@ -335,9 +335,10 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
+       mutex_lock(&dev->struct_mutex);
        if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto err;
        }
 
        if (args->tiling_mode == I915_TILING_NONE) {
@@ -369,7 +370,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                }
        }
 
-       mutex_lock(&dev->struct_mutex);
        if (args->tiling_mode != obj->tiling_mode ||
            args->stride != obj->stride) {
                /* We need to rebind the object if its current allocation
@@ -424,6 +424,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                obj->bit_17 = NULL;
        }
 
+err:
        drm_gem_object_unreference(&obj->base);
        mutex_unlock(&dev->struct_mutex);
 
index 4145d95..ede5bbb 100644 (file)
@@ -1892,6 +1892,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
        u32 iir, gt_iir, pm_iir;
        irqreturn_t ret = IRQ_NONE;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        while (true) {
                /* Find, clear, then process each source of interrupt */
 
@@ -1936,6 +1939,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
        u32 master_ctl, iir;
        irqreturn_t ret = IRQ_NONE;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        for (;;) {
                master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
                iir = I915_READ(VLV_IIR);
@@ -2208,6 +2214,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        /* We get interrupts on unclaimed registers, so check for this before we
         * do any I915_{READ,WRITE}. */
        intel_uncore_check_errors(dev);
@@ -2279,6 +2288,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        enum pipe pipe;
        u32 aux_mask = GEN8_AUX_CHANNEL_A;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        if (IS_GEN9(dev))
                aux_mask |=  GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
                        GEN9_AUX_CHANNEL_D;
@@ -3771,6 +3783,9 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        iir = I915_READ16(IIR);
        if (iir == 0)
                return IRQ_NONE;
@@ -3951,6 +3966,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
        int pipe, ret = IRQ_NONE;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        iir = I915_READ(IIR);
        do {
                bool irq_received = (iir & ~flip_mask) != 0;
@@ -4171,6 +4189,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
+       if (!intel_irqs_enabled(dev_priv))
+               return IRQ_NONE;
+
        iir = I915_READ(IIR);
 
        for (;;) {
@@ -4520,6 +4541,7 @@ void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
 {
        dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
        dev_priv->pm.irqs_enabled = false;
+       synchronize_irq(dev_priv->dev->irq);
 }
 
 /**
index 3d220a6..f75173c 100644 (file)
@@ -37,6 +37,7 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 #include "i915_trace.h"
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_crtc_helper.h>
@@ -2371,13 +2372,19 @@ intel_alloc_plane_obj(struct intel_crtc *crtc,
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_gem_object *obj = NULL;
        struct drm_mode_fb_cmd2 mode_cmd = { 0 };
-       u32 base = plane_config->base;
+       u32 base_aligned = round_down(plane_config->base, PAGE_SIZE);
+       u32 size_aligned = round_up(plane_config->base + plane_config->size,
+                                   PAGE_SIZE);
+
+       size_aligned -= base_aligned;
 
        if (plane_config->size == 0)
                return false;
 
-       obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base,
-                                                            plane_config->size);
+       obj = i915_gem_object_create_stolen_for_preallocated(dev,
+                                                            base_aligned,
+                                                            base_aligned,
+                                                            size_aligned);
        if (!obj)
                return false;
 
@@ -2410,6 +2417,14 @@ out_unref_obj:
        return false;
 }
 
+/* Update plane->state->fb to match plane->fb after driver-internal updates */
+static void
+update_state_fb(struct drm_plane *plane)
+{
+       if (plane->fb != plane->state->fb)
+               drm_atomic_set_fb_for_plane(plane->state, plane->fb);
+}
+
 static void
 intel_find_plane_obj(struct intel_crtc *intel_crtc,
                     struct intel_initial_plane_config *plane_config)
@@ -2423,8 +2438,15 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc,
        if (!intel_crtc->base.primary->fb)
                return;
 
-       if (intel_alloc_plane_obj(intel_crtc, plane_config))
+       if (intel_alloc_plane_obj(intel_crtc, plane_config)) {
+               struct drm_plane *primary = intel_crtc->base.primary;
+
+               primary->state->crtc = &intel_crtc->base;
+               primary->crtc = &intel_crtc->base;
+               update_state_fb(primary);
+
                return;
+       }
 
        kfree(intel_crtc->base.primary->fb);
        intel_crtc->base.primary->fb = NULL;
@@ -2447,15 +2469,21 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc,
                        continue;
 
                if (i915_gem_obj_ggtt_offset(obj) == plane_config->base) {
+                       struct drm_plane *primary = intel_crtc->base.primary;
+
                        if (obj->tiling_mode != I915_TILING_NONE)
                                dev_priv->preserve_bios_swizzle = true;
 
                        drm_framebuffer_reference(c->primary->fb);
-                       intel_crtc->base.primary->fb = c->primary->fb;
+                       primary->fb = c->primary->fb;
+                       primary->state->crtc = &intel_crtc->base;
+                       primary->crtc = &intel_crtc->base;
                        obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
                        break;
                }
        }
+
+       update_state_fb(intel_crtc->base.primary);
 }
 
 static void i9xx_update_primary_plane(struct drm_crtc *crtc,
@@ -2725,10 +2753,19 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
        case DRM_FORMAT_XRGB8888:
                plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
                break;
+       case DRM_FORMAT_ARGB8888:
+               plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
+               plane_ctl |= PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+               break;
        case DRM_FORMAT_XBGR8888:
                plane_ctl |= PLANE_CTL_ORDER_RGBX;
                plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
                break;
+       case DRM_FORMAT_ABGR8888:
+               plane_ctl |= PLANE_CTL_ORDER_RGBX;
+               plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
+               plane_ctl |= PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+               break;
        case DRM_FORMAT_XRGB2101010:
                plane_ctl |= PLANE_CTL_FORMAT_XRGB_2101010;
                break;
@@ -6587,6 +6624,10 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
 
+       val = I915_READ(DSPCNTR(plane));
+       if (!(val & DISPLAY_PLANE_ENABLE))
+               return;
+
        intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
        if (!intel_fb) {
                DRM_DEBUG_KMS("failed to alloc fb\n");
@@ -6595,8 +6636,6 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
 
        fb = &intel_fb->base;
 
-       val = I915_READ(DSPCNTR(plane));
-
        if (INTEL_INFO(dev)->gen >= 4)
                if (val & DISPPLANE_TILED)
                        plane_config->tiling = I915_TILING_X;
@@ -6627,7 +6666,7 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
        aligned_height = intel_fb_align_height(dev, fb->height,
                                               plane_config->tiling);
 
-       plane_config->size = PAGE_ALIGN(fb->pitches[0] * aligned_height);
+       plane_config->size = fb->pitches[0] * aligned_height;
 
        DRM_DEBUG_KMS("pipe/plane %c/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
                      pipe_name(pipe), plane, fb->width, fb->height,
@@ -7628,6 +7667,9 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        fb = &intel_fb->base;
 
        val = I915_READ(PLANE_CTL(pipe, 0));
+       if (!(val & PLANE_CTL_ENABLE))
+               goto error;
+
        if (val & PLANE_CTL_TILED_MASK)
                plane_config->tiling = I915_TILING_X;
 
@@ -7664,7 +7706,7 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
        aligned_height = intel_fb_align_height(dev, fb->height,
                                               plane_config->tiling);
 
-       plane_config->size = ALIGN(fb->pitches[0] * aligned_height, PAGE_SIZE);
+       plane_config->size = fb->pitches[0] * aligned_height;
 
        DRM_DEBUG_KMS("pipe %c with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
                      pipe_name(pipe), fb->width, fb->height,
@@ -7715,6 +7757,10 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc,
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
 
+       val = I915_READ(DSPCNTR(pipe));
+       if (!(val & DISPLAY_PLANE_ENABLE))
+               return;
+
        intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
        if (!intel_fb) {
                DRM_DEBUG_KMS("failed to alloc fb\n");
@@ -7723,8 +7769,6 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc,
 
        fb = &intel_fb->base;
 
-       val = I915_READ(DSPCNTR(pipe));
-
        if (INTEL_INFO(dev)->gen >= 4)
                if (val & DISPPLANE_TILED)
                        plane_config->tiling = I915_TILING_X;
@@ -7755,7 +7799,7 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc,
        aligned_height = intel_fb_align_height(dev, fb->height,
                                               plane_config->tiling);
 
-       plane_config->size = PAGE_ALIGN(fb->pitches[0] * aligned_height);
+       plane_config->size = fb->pitches[0] * aligned_height;
 
        DRM_DEBUG_KMS("pipe %c with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
                      pipe_name(pipe), fb->width, fb->height,
@@ -8698,6 +8742,7 @@ retry:
                        old->release_fb->funcs->destroy(old->release_fb);
                goto fail;
        }
+       crtc->primary->crtc = crtc;
 
        /* let the connector get through one full cycle before testing */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
@@ -9700,7 +9745,7 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       WARN_ON(!in_irq());
+       WARN_ON(!in_interrupt());
 
        if (crtc == NULL)
                return;
@@ -9800,6 +9845,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        drm_gem_object_reference(&obj->base);
 
        crtc->primary->fb = fb;
+       update_state_fb(crtc->primary);
 
        work->pending_flip_obj = obj;
 
@@ -9868,6 +9914,7 @@ cleanup_unpin:
 cleanup_pending:
        atomic_dec(&intel_crtc->unpin_work_count);
        crtc->primary->fb = old_fb;
+       update_state_fb(crtc->primary);
        drm_gem_object_unreference(&work->old_fb_obj->base);
        drm_gem_object_unreference(&obj->base);
        mutex_unlock(&dev->struct_mutex);
@@ -12182,9 +12229,6 @@ intel_check_cursor_plane(struct drm_plane *plane,
                return -ENOMEM;
        }
 
-       if (fb == crtc->cursor->fb)
-               return 0;
-
        /* we only need to pin inside GTT if cursor is non-phy */
        mutex_lock(&dev->struct_mutex);
        if (!INTEL_INFO(dev)->cursor_needs_physical && obj->tiling_mode) {
@@ -13096,6 +13140,9 @@ static struct intel_quirk intel_quirks[] = {
 
        /* HP Chromebook 14 (Celeron 2955U) */
        { 0x0a06, 0x103c, 0x21ed, quirk_backlight_present },
+
+       /* Dell Chromebook 11 */
+       { 0x0a06, 0x1028, 0x0a35, quirk_backlight_present },
 };
 
 static void intel_init_quirks(struct drm_device *dev)
@@ -13702,6 +13749,7 @@ void intel_modeset_gem_init(struct drm_device *dev)
                                  to_intel_crtc(c)->pipe);
                        drm_framebuffer_unreference(c->primary->fb);
                        c->primary->fb = NULL;
+                       update_state_fb(c->primary);
                }
        }
        mutex_unlock(&dev->struct_mutex);
index 04e248d..54daa66 100644 (file)
@@ -282,16 +282,6 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
        return ret;
 }
 
-static bool
-__cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
-                                     enum pipe pipe)
-{
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-       return !intel_crtc->cpu_fifo_underrun_disabled;
-}
-
 /**
  * intel_set_pch_fifo_underrun_reporting - set PCH fifo underrun reporting state
  * @dev_priv: i915 device instance
@@ -352,9 +342,15 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
 void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
                                         enum pipe pipe)
 {
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+       /* We may be called too early in init, thanks BIOS! */
+       if (crtc == NULL)
+               return;
+
        /* GMCH can't disable fifo underruns, filter them. */
        if (HAS_GMCH_DISPLAY(dev_priv->dev) &&
-           !__cpu_fifo_underrun_reporting_enabled(dev_priv, pipe))
+           to_intel_crtc(crtc)->cpu_fifo_underrun_disabled)
                return;
 
        if (intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false))
index 0f358c5..e8d3da9 100644 (file)
@@ -503,18 +503,19 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
                 * If there isn't a request associated with this submission,
                 * create one as a temporary holder.
                 */
-               WARN(1, "execlist context submission without request");
                request = kzalloc(sizeof(*request), GFP_KERNEL);
                if (request == NULL)
                        return -ENOMEM;
                request->ring = ring;
                request->ctx = to;
+               kref_init(&request->ref);
+               request->uniq = dev_priv->request_uniq++;
+               i915_gem_context_reference(request->ctx);
        } else {
+               i915_gem_request_reference(request);
                WARN_ON(to != request->ctx);
        }
        request->tail = tail;
-       i915_gem_request_reference(request);
-       i915_gem_context_reference(request->ctx);
 
        intel_runtime_pm_get(dev_priv);
 
@@ -731,7 +732,6 @@ void intel_execlists_retire_requests(struct intel_engine_cs *ring)
                if (ctx_obj && (ctx != ring->default_context))
                        intel_lr_context_unpin(ring, ctx);
                intel_runtime_pm_put(dev_priv);
-               i915_gem_context_unreference(ctx);
                list_del(&req->execlist_link);
                i915_gem_request_unreference(req);
        }
index 0a52c44..9c5451c 100644 (file)
@@ -1322,7 +1322,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
        drm_modeset_lock_all(dev);
 
        plane = drm_plane_find(dev, set->plane_id);
-       if (!plane) {
+       if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) {
                ret = -ENOENT;
                goto out_unlock;
        }
@@ -1349,7 +1349,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
        drm_modeset_lock_all(dev);
 
        plane = drm_plane_find(dev, get->plane_id);
-       if (!plane) {
+       if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) {
                ret = -ENOENT;
                goto out_unlock;
        }
index c47a3ba..4e8fb89 100644 (file)
@@ -1048,8 +1048,14 @@ static void intel_uncore_fw_domains_init(struct drm_device *dev)
 
                /* We need to init first for ECOBUS access and then
                 * determine later if we want to reinit, in case of MT access is
-                * not working
+                * not working. In this stage we don't know which flavour this
+                * ivb is, so it is better to reset also the gen6 fw registers
+                * before the ecobus check.
                 */
+
+               __raw_i915_write32(dev_priv, FORCEWAKE, 0);
+               __raw_posting_read(dev_priv, ECOBUS);
+
                fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
                               FORCEWAKE_MT, FORCEWAKE_MT_ACK);
 
index 121d30c..87fe8ed 100644 (file)
@@ -70,7 +70,9 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
                118800000, { 0x091c, 0x091c, 0x06dc },
        }, {
                216000000, { 0x06dc, 0x0b5c, 0x091c },
-       }
+       }, {
+               ~0UL, { 0x0000, 0x0000, 0x0000 },
+       },
 };
 
 static const struct dw_hdmi_sym_term imx_sym_term[] = {
@@ -136,11 +138,34 @@ static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
        .destroy = drm_encoder_cleanup,
 };
 
+static enum drm_mode_status imx6q_hdmi_mode_valid(struct drm_connector *con,
+                                                 struct drm_display_mode *mode)
+{
+       if (mode->clock < 13500)
+               return MODE_CLOCK_LOW;
+       if (mode->clock > 266000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,
+                                                  struct drm_display_mode *mode)
+{
+       if (mode->clock < 13500)
+               return MODE_CLOCK_LOW;
+       if (mode->clock > 270000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
 static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
-       .mpll_cfg = imx_mpll_cfg,
-       .cur_ctr  = imx_cur_ctr,
-       .sym_term = imx_sym_term,
-       .dev_type = IMX6Q_HDMI,
+       .mpll_cfg   = imx_mpll_cfg,
+       .cur_ctr    = imx_cur_ctr,
+       .sym_term   = imx_sym_term,
+       .dev_type   = IMX6Q_HDMI,
+       .mode_valid = imx6q_hdmi_mode_valid,
 };
 
 static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
@@ -148,6 +173,7 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
        .cur_ctr  = imx_cur_ctr,
        .sym_term = imx_sym_term,
        .dev_type = IMX6DL_HDMI,
+       .mode_valid = imx6dl_hdmi_mode_valid,
 };
 
 static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
index 1b86aac..2d6dc94 100644 (file)
@@ -163,22 +163,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
 {
        struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
        struct imx_ldb *ldb = imx_ldb_ch->ldb;
-       struct drm_display_mode *mode = &encoder->crtc->hwmode;
        u32 pixel_fmt;
-       unsigned long serial_clk;
-       unsigned long di_clk = mode->clock * 1000;
-       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
-
-       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-               /* dual channel LVDS mode */
-               serial_clk = 3500UL * mode->clock;
-               imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
-               imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
-       } else {
-               serial_clk = 7000UL * mode->clock;
-               imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
-                               di_clk);
-       }
 
        switch (imx_ldb_ch->chno) {
        case 0:
@@ -247,6 +232,9 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
        struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
        struct imx_ldb *ldb = imx_ldb_ch->ldb;
        int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
+       unsigned long serial_clk;
+       unsigned long di_clk = mode->clock * 1000;
+       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
 
        if (mode->clock > 170000) {
                dev_warn(ldb->dev,
@@ -257,6 +245,16 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
                         "%s: mode exceeds 85 MHz pixel clock\n", __func__);
        }
 
+       if (dual) {
+               serial_clk = 3500UL * mode->clock;
+               imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
+               imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
+       } else {
+               serial_clk = 7000UL * mode->clock;
+               imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
+                                 di_clk);
+       }
+
        /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
        if (imx_ldb_ch == &ldb->channel[0]) {
                if (mode->flags & DRM_MODE_FLAG_NVSYNC)
index 5e83e00..900dda6 100644 (file)
@@ -236,8 +236,11 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
        }
 
        panel_node = of_parse_phandle(np, "fsl,panel", 0);
-       if (panel_node)
+       if (panel_node) {
                imxpd->panel = of_drm_find_panel(panel_node);
+               if (!imxpd->panel)
+                       return -EPROBE_DEFER;
+       }
 
        imxpd->dev = dev;
 
index 8edd531..7369ee7 100644 (file)
@@ -32,7 +32,10 @@ static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
 void mdp4_irq_preinstall(struct msm_kms *kms)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_enable(mdp4_kms);
        mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff);
+       mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+       mdp4_disable(mdp4_kms);
 }
 
 int mdp4_irq_postinstall(struct msm_kms *kms)
@@ -53,7 +56,9 @@ int mdp4_irq_postinstall(struct msm_kms *kms)
 void mdp4_irq_uninstall(struct msm_kms *kms)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_enable(mdp4_kms);
        mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+       mdp4_disable(mdp4_kms);
 }
 
 irqreturn_t mdp4_irq(struct msm_kms *kms)
index 09b4a25..c276624 100644 (file)
@@ -8,17 +8,9 @@ http://github.com/freedreno/envytools/
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml            (  27229 bytes, from 2015-02-10 17:00:41)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2014-06-02 18:31:15)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2015-01-23 16:20:19)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -910,6 +902,7 @@ static inline uint32_t __offset_LM(uint32_t idx)
                case 2: return (mdp5_cfg->lm.base[2]);
                case 3: return (mdp5_cfg->lm.base[3]);
                case 4: return (mdp5_cfg->lm.base[4]);
+               case 5: return (mdp5_cfg->lm.base[5]);
                default: return INVALID_IDX(idx);
        }
 }
index 46fac54..2f2863c 100644 (file)
@@ -62,8 +62,8 @@ struct mdp5_crtc {
 
                /* current cursor being scanned out: */
                struct drm_gem_object *scanout_bo;
-               uint32_t width;
-               uint32_t height;
+               uint32_t width, height;
+               uint32_t x, y;
        } cursor;
 };
 #define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
@@ -103,8 +103,8 @@ static void crtc_flush_all(struct drm_crtc *crtc)
        struct drm_plane *plane;
        uint32_t flush_mask = 0;
 
-       /* we could have already released CTL in the disable path: */
-       if (!mdp5_crtc->ctl)
+       /* this should not happen: */
+       if (WARN_ON(!mdp5_crtc->ctl))
                return;
 
        drm_atomic_crtc_for_each_plane(plane, crtc) {
@@ -143,6 +143,11 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
        drm_atomic_crtc_for_each_plane(plane, crtc) {
                mdp5_plane_complete_flip(plane);
        }
+
+       if (mdp5_crtc->ctl && !crtc->state->enable) {
+               mdp5_ctl_release(mdp5_crtc->ctl);
+               mdp5_crtc->ctl = NULL;
+       }
 }
 
 static void unref_cursor_worker(struct drm_flip_work *work, void *val)
@@ -386,14 +391,17 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
        mdp5_crtc->event = crtc->state->event;
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
+       /*
+        * If no CTL has been allocated in mdp5_crtc_atomic_check(),
+        * it means we are trying to flush a CRTC whose state is disabled:
+        * nothing else needs to be done.
+        */
+       if (unlikely(!mdp5_crtc->ctl))
+               return;
+
        blend_setup(crtc);
        crtc_flush_all(crtc);
        request_pending(crtc, PENDING_FLIP);
-
-       if (mdp5_crtc->ctl && !crtc->state->enable) {
-               mdp5_ctl_release(mdp5_crtc->ctl);
-               mdp5_crtc->ctl = NULL;
-       }
 }
 
 static int mdp5_crtc_set_property(struct drm_crtc *crtc,
@@ -403,6 +411,32 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
        return -EINVAL;
 }
 
+static void get_roi(struct drm_crtc *crtc, uint32_t *roi_w, uint32_t *roi_h)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       uint32_t xres = crtc->mode.hdisplay;
+       uint32_t yres = crtc->mode.vdisplay;
+
+       /*
+        * Cursor Region Of Interest (ROI) is a plane read from cursor
+        * buffer to render. The ROI region is determined by the visibility of
+        * the cursor point. In the default Cursor image the cursor point will
+        * be at the top left of the cursor image, unless it is specified
+        * otherwise using hotspot feature.
+        *
+        * If the cursor point reaches the right (xres - x < cursor.width) or
+        * bottom (yres - y < cursor.height) boundary of the screen, then ROI
+        * width and ROI height need to be evaluated to crop the cursor image
+        * accordingly.
+        * (xres-x) will be new cursor width when x > (xres - cursor.width)
+        * (yres-y) will be new cursor height when y > (yres - cursor.height)
+        */
+       *roi_w = min(mdp5_crtc->cursor.width, xres -
+                       mdp5_crtc->cursor.x);
+       *roi_h = min(mdp5_crtc->cursor.height, yres -
+                       mdp5_crtc->cursor.y);
+}
+
 static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
                struct drm_file *file, uint32_t handle,
                uint32_t width, uint32_t height)
@@ -416,6 +450,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        unsigned int depth;
        enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+       uint32_t roi_w, roi_h;
        unsigned long flags;
 
        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
@@ -446,6 +481,12 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
        old_bo = mdp5_crtc->cursor.scanout_bo;
 
+       mdp5_crtc->cursor.scanout_bo = cursor_bo;
+       mdp5_crtc->cursor.width = width;
+       mdp5_crtc->cursor.height = height;
+
+       get_roi(crtc, &roi_w, &roi_h);
+
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
                        MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
@@ -453,19 +494,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
                        MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
                        MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
-                       MDP5_LM_CURSOR_SIZE_ROI_H(height) |
-                       MDP5_LM_CURSOR_SIZE_ROI_W(width));
+                       MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
+                       MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), cursor_addr);
 
-
        blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
-       blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN;
        blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
 
-       mdp5_crtc->cursor.scanout_bo = cursor_bo;
-       mdp5_crtc->cursor.width = width;
-       mdp5_crtc->cursor.height = height;
        spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
 
        ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
@@ -489,31 +525,18 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
-       uint32_t xres = crtc->mode.hdisplay;
-       uint32_t yres = crtc->mode.vdisplay;
        uint32_t roi_w;
        uint32_t roi_h;
        unsigned long flags;
 
-       x = (x > 0) ? x : 0;
-       y = (y > 0) ? y : 0;
+       /* In case the CRTC is disabled, just drop the cursor update */
+       if (unlikely(!crtc->state->enable))
+               return 0;
 
-       /*
-        * Cursor Region Of Interest (ROI) is a plane read from cursor
-        * buffer to render. The ROI region is determined by the visiblity of
-        * the cursor point. In the default Cursor image the cursor point will
-        * be at the top left of the cursor image, unless it is specified
-        * otherwise using hotspot feature.
-        *
-        * If the cursor point reaches the right (xres - x < cursor.width) or
-        * bottom (yres - y < cursor.height) boundary of the screen, then ROI
-        * width and ROI height need to be evaluated to crop the cursor image
-        * accordingly.
-        * (xres-x) will be new cursor width when x > (xres - cursor.width)
-        * (yres-y) will be new cursor height when y > (yres - cursor.height)
-        */
-       roi_w = min(mdp5_crtc->cursor.width, xres - x);
-       roi_h = min(mdp5_crtc->cursor.height, yres - y);
+       mdp5_crtc->cursor.x = x = max(x, 0);
+       mdp5_crtc->cursor.y = y = max(y, 0);
+
+       get_roi(crtc, &roi_w, &roi_h);
 
        spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(mdp5_crtc->lm),
@@ -544,8 +567,8 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = {
 static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
        .mode_fixup = mdp5_crtc_mode_fixup,
        .mode_set_nofb = mdp5_crtc_mode_set_nofb,
-       .prepare = mdp5_crtc_disable,
-       .commit = mdp5_crtc_enable,
+       .disable = mdp5_crtc_disable,
+       .enable = mdp5_crtc_enable,
        .atomic_check = mdp5_crtc_atomic_check,
        .atomic_begin = mdp5_crtc_atomic_begin,
        .atomic_flush = mdp5_crtc_atomic_flush,
index d6a14bb..af0e02f 100644 (file)
@@ -267,14 +267,14 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
        mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
 
-       mdp5_encoder->enabled = false;
+       mdp5_encoder->enabled = true;
 }
 
 static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
        .mode_fixup = mdp5_encoder_mode_fixup,
        .mode_set = mdp5_encoder_mode_set,
-       .prepare = mdp5_encoder_disable,
-       .commit = mdp5_encoder_enable,
+       .disable = mdp5_encoder_disable,
+       .enable = mdp5_encoder_enable,
 };
 
 /* initialize encoder */
index 70ac81e..a940710 100644 (file)
@@ -34,7 +34,10 @@ static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
 void mdp5_irq_preinstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       mdp5_enable(mdp5_kms);
        mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
+       mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_disable(mdp5_kms);
 }
 
 int mdp5_irq_postinstall(struct msm_kms *kms)
@@ -57,7 +60,9 @@ int mdp5_irq_postinstall(struct msm_kms *kms)
 void mdp5_irq_uninstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       mdp5_enable(mdp5_kms);
        mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_disable(mdp5_kms);
 }
 
 static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
index 871aa21..18fd643 100644 (file)
@@ -219,8 +219,10 @@ int msm_atomic_commit(struct drm_device *dev,
         * mark our set of crtc's as busy:
         */
        ret = start_atomic(dev->dev_private, c->crtc_mask);
-       if (ret)
+       if (ret) {
+               kfree(c);
                return ret;
+       }
 
        /*
         * This is the point of no return - everything below never fails except
index 79924e4..6751553 100644 (file)
@@ -418,7 +418,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
        nouveau_fbcon_zfill(dev, fbcon);
 
        /* To allow resizeing without swapping buffers */
-       NV_INFO(drm, "allocated %dx%d fb: 0x%lx, bo %p\n",
+       NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n",
                nouveau_fb->base.width, nouveau_fb->base.height,
                nvbo->bo.offset, nvbo);
 
index 29bd539..6efa8f3 100644 (file)
@@ -340,11 +340,13 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 
                /* switch mmio to cpu's native endianness */
 #ifndef __BIG_ENDIAN
-               if (ioread32_native(map + 0x000004) != 0x00000000)
+               if (ioread32_native(map + 0x000004) != 0x00000000) {
 #else
-               if (ioread32_native(map + 0x000004) == 0x00000000)
+               if (ioread32_native(map + 0x000004) == 0x00000000) {
 #endif
                        iowrite32_native(0x01000001, map + 0x000004);
+                       ioread32_native(map);
+               }
 
                /* read boot0 and strapping information */
                boot0 = ioread32_native(map + 0x000000);
index 539561e..108d048 100644 (file)
@@ -140,6 +140,49 @@ gm100_identify(struct nvkm_device *device)
                device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
                device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
                device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+#endif
+               break;
+       case 0x126:
+               device->cname = "GM206";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] =  gm204_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
+#if 0
+               /* looks to be some non-trivial changes */
+               device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+               /* priv ring says no to 0x10eb14 writes */
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
+#endif
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm204_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PMU    ] =  gk208_pmu_oclass;
+#if 0
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_CE0    ] = &gm204_ce0_oclass;
+               device->oclass[NVDEV_ENGINE_CE1    ] = &gm204_ce1_oclass;
+               device->oclass[NVDEV_ENGINE_CE2    ] = &gm204_ce2_oclass;
+               device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+               device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+               device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
 #endif
                break;
        default:
index b038b6e..043e429 100644 (file)
@@ -502,72 +502,57 @@ nv04_fifo_intr(struct nvkm_subdev *subdev)
 {
        struct nvkm_device *device = nv_device(subdev);
        struct nv04_fifo_priv *priv = (void *)subdev;
-       uint32_t status, reassign;
-       int cnt = 0;
+       u32 mask = nv_rd32(priv, NV03_PFIFO_INTR_EN_0);
+       u32 stat = nv_rd32(priv, NV03_PFIFO_INTR_0) & mask;
+       u32 reassign, chid, get, sem;
 
        reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
-       while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
-               uint32_t chid, get;
-
-               nv_wr32(priv, NV03_PFIFO_CACHES, 0);
-
-               chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
-               get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
+       nv_wr32(priv, NV03_PFIFO_CACHES, 0);
 
-               if (status & NV_PFIFO_INTR_CACHE_ERROR) {
-                       nv04_fifo_cache_error(device, priv, chid, get);
-                       status &= ~NV_PFIFO_INTR_CACHE_ERROR;
-               }
+       chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+       get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
 
-               if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-                       nv04_fifo_dma_pusher(device, priv, chid);
-                       status &= ~NV_PFIFO_INTR_DMA_PUSHER;
-               }
+       if (stat & NV_PFIFO_INTR_CACHE_ERROR) {
+               nv04_fifo_cache_error(device, priv, chid, get);
+               stat &= ~NV_PFIFO_INTR_CACHE_ERROR;
+       }
 
-               if (status & NV_PFIFO_INTR_SEMAPHORE) {
-                       uint32_t sem;
+       if (stat & NV_PFIFO_INTR_DMA_PUSHER) {
+               nv04_fifo_dma_pusher(device, priv, chid);
+               stat &= ~NV_PFIFO_INTR_DMA_PUSHER;
+       }
 
-                       status &= ~NV_PFIFO_INTR_SEMAPHORE;
-                       nv_wr32(priv, NV03_PFIFO_INTR_0,
-                               NV_PFIFO_INTR_SEMAPHORE);
+       if (stat & NV_PFIFO_INTR_SEMAPHORE) {
+               stat &= ~NV_PFIFO_INTR_SEMAPHORE;
+               nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE);
 
-                       sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
-                       nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+               sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
+               nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
 
-                       nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
-                       nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-               }
+               nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+               nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+       }
 
-               if (device->card_type == NV_50) {
-                       if (status & 0x00000010) {
-                               status &= ~0x00000010;
-                               nv_wr32(priv, 0x002100, 0x00000010);
-                       }
-
-                       if (status & 0x40000000) {
-                               nv_wr32(priv, 0x002100, 0x40000000);
-                               nvkm_fifo_uevent(&priv->base);
-                               status &= ~0x40000000;
-                       }
+       if (device->card_type == NV_50) {
+               if (stat & 0x00000010) {
+                       stat &= ~0x00000010;
+                       nv_wr32(priv, 0x002100, 0x00000010);
                }
 
-               if (status) {
-                       nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
-                               status, chid);
-                       nv_wr32(priv, NV03_PFIFO_INTR_0, status);
-                       status = 0;
+               if (stat & 0x40000000) {
+                       nv_wr32(priv, 0x002100, 0x40000000);
+                       nvkm_fifo_uevent(&priv->base);
+                       stat &= ~0x40000000;
                }
-
-               nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
        }
 
-       if (status) {
-               nv_error(priv, "still angry after %d spins, halt\n", cnt);
-               nv_wr32(priv, 0x002140, 0);
-               nv_wr32(priv, 0x000140, 0);
+       if (stat) {
+               nv_warn(priv, "unknown intr 0x%08x\n", stat);
+               nv_mask(priv, NV03_PFIFO_INTR_EN_0, stat, 0x00000000);
+               nv_wr32(priv, NV03_PFIFO_INTR_0, stat);
        }
 
-       nv_wr32(priv, 0x000100, 0x00000100);
+       nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
 }
 
 static int
index 2e7ec38..57e2c5b 100644 (file)
@@ -1032,9 +1032,9 @@ gf100_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418808, 0x00000000, s, b);
-       mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s));
 }
 
 void
index b52300d..5e9454b 100644 (file)
@@ -851,9 +851,9 @@ gk104_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418808, 0x00000000, s, b);
-       mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s));
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
index 956f4dc..b2fae6e 100644 (file)
@@ -871,9 +871,9 @@ gm107_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418e24, 0x00000000, s, b);
-       mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s));
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
index d1a89b2..c4e1f08 100644 (file)
@@ -74,7 +74,11 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info)
        u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
        if (ent) {
                if (ver >= 0x41) {
-                       if (!(nv_ro32(bios, ent) & 0x80000000))
+                       u32 ent_value = nv_ro32(bios, ent);
+                       u8 i2c_port = (ent_value >> 27) & 0x1f;
+                       u8 dpaux_port = (ent_value >> 22) & 0x1f;
+                       /* value 0x1f means unused according to DCB 4.x spec */
+                       if (i2c_port == 0x1f && dpaux_port == 0x1f)
                                info->type = DCB_I2C_UNUSED;
                        else
                                info->type = DCB_I2C_PMGR;
index ed644a4..86807ee 100644 (file)
@@ -1405,6 +1405,9 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
               (x << 16) | y);
        viewport_w = crtc->mode.hdisplay;
        viewport_h = (crtc->mode.vdisplay + 1) & ~1;
+       if ((rdev->family >= CHIP_BONAIRE) &&
+           (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE))
+               viewport_h *= 2;
        WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
               (viewport_w << 16) | viewport_h);
 
index 5bf825d..8d74de8 100644 (file)
@@ -178,6 +178,13 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        switch (msg->request & ~DP_AUX_I2C_MOT) {
        case DP_AUX_NATIVE_WRITE:
        case DP_AUX_I2C_WRITE:
+               /* The atom implementation only supports writes with a max payload of
+                * 12 bytes since it uses 4 bits for the total count (header + payload)
+                * in the parameter space.  The atom interface supports 16 byte
+                * payloads for reads. The hw itself supports up to 16 bytes of payload.
+                */
+               if (WARN_ON_ONCE(msg->size > 12))
+                       return -E2BIG;
                /* tx_size needs to be 4 even for bare address packets since the atom
                 * table needs the info in tx_buf[3].
                 */
index 7c9df1e..c39c1d0 100644 (file)
@@ -731,7 +731,9 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                dig_connector = radeon_connector->con_priv;
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
-                       if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
+                       if (radeon_audio != 0 &&
+                           drm_detect_monitor_audio(radeon_connector_edid(connector)) &&
+                           ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
                                return ATOM_ENCODER_MODE_DP_AUDIO;
                        return ATOM_ENCODER_MODE_DP;
                } else if (radeon_audio != 0) {
@@ -747,7 +749,9 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                }
                break;
        case DRM_MODE_CONNECTOR_eDP:
-               if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
+               if (radeon_audio != 0 &&
+                   drm_detect_monitor_audio(radeon_connector_edid(connector)) &&
+                   ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
                        return ATOM_ENCODER_MODE_DP_AUDIO;
                return ATOM_ENCODER_MODE_DP;
        case DRM_MODE_CONNECTOR_DVIA:
@@ -1622,7 +1626,6 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
        struct radeon_connector *radeon_connector = NULL;
        struct radeon_connector_atom_dig *radeon_dig_connector = NULL;
        bool travis_quirk = false;
-       int encoder_mode;
 
        if (connector) {
                radeon_connector = to_radeon_connector(connector);
@@ -1718,11 +1721,6 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
                }
                break;
        }
-
-       encoder_mode = atombios_get_encoder_mode(encoder);
-       if (radeon_audio != 0 &&
-               (encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode)))
-               radeon_audio_dpms(encoder, mode);
 }
 
 static void
@@ -1731,10 +1729,19 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       int encoder_mode = atombios_get_encoder_mode(encoder);
 
        DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
                  radeon_encoder->encoder_id, mode, radeon_encoder->devices,
                  radeon_encoder->active_device);
+
+       if (connector && (radeon_audio != 0) &&
+           ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
+            (ENCODER_MODE_IS_DP(encoder_mode) &&
+             drm_detect_monitor_audio(radeon_connector_edid(connector)))))
+               radeon_audio_dpms(encoder, mode);
+
        switch (radeon_encoder->encoder_id) {
        case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
@@ -2136,6 +2143,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int encoder_mode;
 
        radeon_encoder->pixel_clock = adjusted_mode->clock;
@@ -2163,10 +2171,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
                /* handled in dpms */
-               encoder_mode = atombios_get_encoder_mode(encoder);
-               if (radeon_audio != 0 &&
-                       (encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode)))
-                       radeon_audio_mode_set(encoder, adjusted_mode);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DDI:
        case ENCODER_OBJECT_ID_INTERNAL_DVO1:
@@ -2188,6 +2192,13 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        atombios_apply_encoder_quirks(encoder, adjusted_mode);
+
+       encoder_mode = atombios_get_encoder_mode(encoder);
+       if (connector && (radeon_audio != 0) &&
+           ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
+            (ENCODER_MODE_IS_DP(encoder_mode) &&
+             drm_detect_monitor_audio(radeon_connector_edid(connector)))))
+               radeon_audio_mode_set(encoder, adjusted_mode);
 }
 
 static bool
index e6a4ba2..3e670d3 100644 (file)
@@ -3613,6 +3613,8 @@ static void cik_gpu_init(struct radeon_device *rdev)
        }
 
        WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 0x1);
+       WREG32(SRBM_INT_ACK, 0x1);
 
        WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
 
@@ -7230,6 +7232,8 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev)
        WREG32(CP_ME2_PIPE3_INT_CNTL, 0);
        /* grbm */
        WREG32(GRBM_INT_CNTL, 0);
+       /* SRBM */
+       WREG32(SRBM_INT_CNTL, 0);
        /* vline/vblank, etc. */
        WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
        WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@@ -7551,6 +7555,9 @@ int cik_irq_set(struct radeon_device *rdev)
        WREG32(DC_HPD5_INT_CONTROL, hpd5);
        WREG32(DC_HPD6_INT_CONTROL, hpd6);
 
+       /* posting read */
+       RREG32(SRBM_STATUS);
+
        return 0;
 }
 
@@ -8046,6 +8053,10 @@ restart_ih:
                                break;
                        }
                        break;
+               case 96:
+                       DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+                       WREG32(SRBM_INT_ACK, 0x1);
+                       break;
                case 124: /* UVD */
                        DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
                        radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
index 03003f8..243a36c 100644 (file)
 #define                SOFT_RESET_ORB                          (1 << 23)
 #define                SOFT_RESET_VCE                          (1 << 24)
 
+#define SRBM_READ_ERROR                                        0xE98
+#define SRBM_INT_CNTL                                  0xEA0
+#define SRBM_INT_ACK                                   0xEA8
+
 #define VM_L2_CNTL                                     0x1400
 #define                ENABLE_L2_CACHE                                 (1 << 0)
 #define                ENABLE_L2_FRAGMENT_PROCESSING                   (1 << 1)
 #define VCE_UENC_REG_CLOCK_GATING      0x207c0
 #define VCE_SYS_INT_EN                 0x21300
 #      define VCE_SYS_INT_TRAP_INTERRUPT_EN    (1 << 3)
+#define VCE_LMI_VCPU_CACHE_40BIT_BAR   0x2145c
 #define VCE_LMI_CTRL2                  0x21474
 #define VCE_LMI_CTRL                   0x21498
 #define VCE_LMI_VM_CTRL                        0x214a0
index 192c803..3adc2af 100644 (file)
@@ -26,6 +26,9 @@
 #include "radeon_audio.h"
 #include "sid.h"
 
+#define DCE8_DCCG_AUDIO_DTO1_PHASE     0x05b8
+#define DCE8_DCCG_AUDIO_DTO1_MODULE    0x05bc
+
 u32 dce6_endpoint_rreg(struct radeon_device *rdev,
                              u32 block_offset, u32 reg)
 {
@@ -252,72 +255,67 @@ void dce6_audio_enable(struct radeon_device *rdev,
 void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
        struct radeon_crtc *crtc, unsigned int clock)
 {
-    /* Two dtos; generally use dto0 for HDMI */
+       /* Two dtos; generally use dto0 for HDMI */
        u32 value = 0;
 
-    if (crtc)
+       if (crtc)
                value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
        WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
-    /* Express [24MHz / target pixel clock] as an exact rational
-     * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
-     * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
-     */
-    WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
-    WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
+       /* Express [24MHz / target pixel clock] as an exact rational
+        * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+        * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+        */
+       WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
+       WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
 }
 
 void dce6_dp_audio_set_dto(struct radeon_device *rdev,
        struct radeon_crtc *crtc, unsigned int clock)
 {
-    /* Two dtos; generally use dto1 for DP */
+       /* Two dtos; generally use dto1 for DP */
        u32 value = 0;
        value |= DCCG_AUDIO_DTO_SEL;
 
-    if (crtc)
+       if (crtc)
                value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
        WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
-    /* Express [24MHz / target pixel clock] as an exact rational
-     * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
-     * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
-     */
-    WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
-    WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+       /* Express [24MHz / target pixel clock] as an exact rational
+        * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+        * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+        */
+       if (ASIC_IS_DCE8(rdev)) {
+               WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000);
+               WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock);
+       } else {
+               WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
+               WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+       }
 }
 
-void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+void dce6_dp_enable(struct drm_encoder *encoder, bool enable)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       uint32_t offset;
 
        if (!dig || !dig->afmt)
                return;
 
-       offset = dig->afmt->offset;
-
        if (enable) {
-        if (dig->afmt->enabled)
-            return;
-
-               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset,
-                       EVERGREEN_DP_SEC_ASP_ENABLE |           /* Audio packet transmission */
-                       EVERGREEN_DP_SEC_ATP_ENABLE |           /* Audio timestamp packet transmission */
-                       EVERGREEN_DP_SEC_AIP_ENABLE |           /* Audio infoframe packet transmission */
-                       EVERGREEN_DP_SEC_STREAM_ENABLE);        /* Master enable for secondary stream engine */
-               radeon_audio_enable(rdev, dig->afmt->pin, true);
+               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_ASP_ENABLE |            /* Audio packet transmission */
+                      EVERGREEN_DP_SEC_ATP_ENABLE |            /* Audio timestamp packet transmission */
+                      EVERGREEN_DP_SEC_AIP_ENABLE |            /* Audio infoframe packet transmission */
+                      EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */
        } else {
-               if (!dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
-               radeon_audio_enable(rdev, dig->afmt->pin, false);
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
index 78600f5..973df06 100644 (file)
@@ -3253,6 +3253,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        }
 
        WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 0x1);
+       WREG32(SRBM_INT_ACK, 0x1);
 
        evergreen_fix_pci_max_read_req_size(rdev);
 
@@ -4324,6 +4326,7 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
        tmp = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
        WREG32(DMA_CNTL, tmp);
        WREG32(GRBM_INT_CNTL, 0);
+       WREG32(SRBM_INT_CNTL, 0);
        WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
        WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
        if (rdev->num_crtc >= 4) {
@@ -4590,6 +4593,9 @@ int evergreen_irq_set(struct radeon_device *rdev)
        WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, afmt5);
        WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, afmt6);
 
+       /* posting read */
+       RREG32(SRBM_STATUS);
+
        return 0;
 }
 
@@ -5066,6 +5072,10 @@ restart_ih:
                                DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
                        }
+               case 96:
+                       DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+                       WREG32(SRBM_INT_ACK, 0x1);
+                       break;
                case 124: /* UVD */
                        DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
                        radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
index 1d9aebc..c18d4ec 100644 (file)
@@ -272,7 +272,7 @@ void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
 }
 
 void dce4_dp_audio_set_dto(struct radeon_device *rdev,
-       struct radeon_crtc *crtc, unsigned int clock)
+                          struct radeon_crtc *crtc, unsigned int clock)
 {
        u32 value;
 
@@ -294,7 +294,7 @@ void dce4_dp_audio_set_dto(struct radeon_device *rdev,
         * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
         */
        WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
-       WREG32(DCCG_AUDIO_DTO1_MODULE, rdev->clock.max_pixel_clock * 10);
+       WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
 }
 
 void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
@@ -350,20 +350,9 @@ void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
 
-       WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
-               HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
-               HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
-
        WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
                AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
 
-       WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
-               HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
-
-       WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
-               HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
-               HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
-
        WREG32(AFMT_60958_0 + offset,
                AFMT_60958_CS_CHANNEL_NUMBER_L(1));
 
@@ -408,15 +397,19 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!dig || !dig->afmt)
                return;
 
-       /* Silent, r600_hdmi_enable will raise WARN for us */
-       if (enable && dig->afmt->enabled)
-               return;
-       if (!enable && !dig->afmt->enabled)
-               return;
+       if (enable) {
+               WREG32(HDMI_INFOFRAME_CONTROL1 + dig->afmt->offset,
+                      HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
+
+               WREG32(HDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset,
+                      HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
+                      HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
 
-       if (!enable && dig->afmt->pin) {
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
-               dig->afmt->pin = NULL;
+               WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset,
+                      HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+                      HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
+       } else {
+               WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
@@ -425,33 +418,28 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
                  enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
 }
 
-void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+void evergreen_dp_enable(struct drm_encoder *encoder, bool enable)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       uint32_t offset;
 
        if (!dig || !dig->afmt)
                return;
 
-       offset = dig->afmt->offset;
-
        if (enable) {
                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                struct radeon_connector_atom_dig *dig_connector;
                uint32_t val;
 
-               if (dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
 
                if (radeon_connector->con_priv) {
                        dig_connector = radeon_connector->con_priv;
-                       val = RREG32(EVERGREEN_DP_SEC_AUD_N + offset);
+                       val = RREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset);
                        val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf);
 
                        if (dig_connector->dp_clock == 162000)
@@ -459,21 +447,16 @@ void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
                        else
                                val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5);
 
-                       WREG32(EVERGREEN_DP_SEC_AUD_N + offset, val);
+                       WREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset, val);
                }
 
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset,
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset,
                        EVERGREEN_DP_SEC_ASP_ENABLE |           /* Audio packet transmission */
                        EVERGREEN_DP_SEC_ATP_ENABLE |           /* Audio timestamp packet transmission */
                        EVERGREEN_DP_SEC_AIP_ENABLE |           /* Audio infoframe packet transmission */
                        EVERGREEN_DP_SEC_STREAM_ENABLE);        /* Master enable for secondary stream engine */
-               radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
        } else {
-               if (!dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
index ee83d2a..a8d1d52 100644 (file)
 #define                SOFT_RESET_REGBB                        (1 << 22)
 #define                SOFT_RESET_ORB                          (1 << 23)
 
+#define SRBM_READ_ERROR                                        0xE98
+#define SRBM_INT_CNTL                                  0xEA0
+#define SRBM_INT_ACK                                   0xEA8
+
 /* display watermarks */
 #define        DC_LB_MEMORY_SPLIT                                0x6b0c
 #define        PRIORITY_A_CNT                                    0x6b18
index 24242a7..dab0081 100644 (file)
@@ -962,6 +962,8 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        }
 
        WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 0x1);
+       WREG32(SRBM_INT_ACK, 0x1);
 
        evergreen_fix_pci_max_read_req_size(rdev);
 
@@ -1086,12 +1088,12 @@ static void cayman_gpu_init(struct radeon_device *rdev)
 
        if ((rdev->config.cayman.max_backends_per_se == 1) &&
            (rdev->flags & RADEON_IS_IGP)) {
-               if ((disabled_rb_mask & 3) == 1) {
-                       /* RB0 disabled, RB1 enabled */
-                       tmp = 0x11111111;
-               } else {
+               if ((disabled_rb_mask & 3) == 2) {
                        /* RB1 disabled, RB0 enabled */
                        tmp = 0x00000000;
+               } else {
+                       /* RB0 disabled, RB1 enabled */
+                       tmp = 0x11111111;
                }
        } else {
                tmp = gb_addr_config & NUM_PIPES_MASK;
index ad71254..6b44580 100644 (file)
 #define                SOFT_RESET_REGBB                        (1 << 22)
 #define                SOFT_RESET_ORB                          (1 << 23)
 
+#define SRBM_READ_ERROR                                        0xE98
+#define SRBM_INT_CNTL                                  0xEA0
+#define SRBM_INT_ACK                                   0xEA8
+
 #define        SRBM_STATUS2                                    0x0EC4
 #define                DMA_BUSY                                (1 << 5)
 #define                DMA1_BUSY                               (1 << 6)
index 279801c..04f2514 100644 (file)
@@ -728,6 +728,10 @@ int r100_irq_set(struct radeon_device *rdev)
                tmp |= RADEON_FP2_DETECT_MASK;
        }
        WREG32(RADEON_GEN_INT_CNTL, tmp);
+
+       /* read back to post the write */
+       RREG32(RADEON_GEN_INT_CNTL);
+
        return 0;
 }
 
index 07a71a2..2fcad34 100644 (file)
@@ -3784,6 +3784,9 @@ int r600_irq_set(struct radeon_device *rdev)
                WREG32(RV770_CG_THERMAL_INT, thermal_int);
        }
 
+       /* posting read */
+       RREG32(R_000E50_SRBM_STATUS);
+
        return 0;
 }
 
index 843b65f..fa21544 100644 (file)
@@ -188,7 +188,7 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev)
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        radeon_crtc = to_radeon_crtc(crtc);
                        if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
-                               vrefresh = radeon_crtc->hw_mode.vrefresh;
+                               vrefresh = drm_mode_vrefresh(&radeon_crtc->hw_mode);
                                break;
                        }
                }
index 62c91ed..dd6606b 100644 (file)
@@ -476,17 +476,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!dig || !dig->afmt)
                return;
 
-       /* Silent, r600_hdmi_enable will raise WARN for us */
-       if (enable && dig->afmt->enabled)
-               return;
-       if (!enable && !dig->afmt->enabled)
-               return;
-
-       if (!enable && dig->afmt->pin) {
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
-               dig->afmt->pin = NULL;
-       }
-
        /* Older chipsets require setting HDMI and routing manually */
        if (!ASIC_IS_DCE3(rdev)) {
                if (enable)
index 5587603..33d5a4f 100644 (file)
@@ -1565,6 +1565,7 @@ struct radeon_dpm {
        int                     new_active_crtc_count;
        u32                     current_active_crtcs;
        int                     current_active_crtc_count;
+       bool single_display;
        struct radeon_dpm_dynamic_state dyn_state;
        struct radeon_dpm_fan fan;
        u32 tdp_limit;
index a3ceef6..b21ef69 100644 (file)
@@ -101,8 +101,8 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
        struct drm_display_mode *mode);
 void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
-void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
-void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
+void evergreen_dp_enable(struct drm_encoder *encoder, bool enable);
+void dce6_dp_enable(struct drm_encoder *encoder, bool enable);
 
 static const u32 pin_offsets[7] =
 {
@@ -210,7 +210,7 @@ static struct radeon_audio_funcs dce4_dp_funcs = {
        .set_avi_packet = evergreen_set_avi_packet,
        .set_audio_packet = dce4_set_audio_packet,
        .mode_set = radeon_audio_dp_mode_set,
-       .dpms = evergreen_enable_dp_audio_packets,
+       .dpms = evergreen_dp_enable,
 };
 
 static struct radeon_audio_funcs dce6_hdmi_funcs = {
@@ -240,7 +240,7 @@ static struct radeon_audio_funcs dce6_dp_funcs = {
        .set_avi_packet = evergreen_set_avi_packet,
        .set_audio_packet = dce4_set_audio_packet,
        .mode_set = radeon_audio_dp_mode_set,
-       .dpms = dce6_enable_dp_audio_packets,
+       .dpms = dce6_dp_enable,
 };
 
 static void radeon_audio_interface_init(struct radeon_device *rdev)
@@ -452,7 +452,7 @@ void radeon_audio_enable(struct radeon_device *rdev,
 }
 
 void radeon_audio_detect(struct drm_connector *connector,
-       enum drm_connector_status status)
+                        enum drm_connector_status status)
 {
        struct radeon_device *rdev;
        struct radeon_encoder *radeon_encoder;
@@ -483,14 +483,11 @@ void radeon_audio_detect(struct drm_connector *connector,
                else
                        radeon_encoder->audio = rdev->audio.hdmi_funcs;
 
-               radeon_audio_write_speaker_allocation(connector->encoder);
-               radeon_audio_write_sad_regs(connector->encoder);
-               if (connector->encoder->crtc)
-                       radeon_audio_write_latency_fields(connector->encoder,
-                               &connector->encoder->crtc->mode);
+               dig->afmt->pin = radeon_audio_get_pin(connector->encoder);
                radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
        } else {
                radeon_audio_enable(rdev, dig->afmt->pin, 0);
+               dig->afmt->pin = NULL;
        }
 }
 
@@ -694,23 +691,22 @@ static void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute)
  * update the info frames with the data from the current display mode
  */
 static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                                      struct drm_display_mode *mode)
 {
-       struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 
        if (!dig || !dig->afmt)
                return;
 
-       /* disable audio prior to setting up hw */
-       dig->afmt->pin = radeon_audio_get_pin(encoder);
-       radeon_audio_enable(rdev, dig->afmt->pin, 0);
+       radeon_audio_set_mute(encoder, true);
 
+       radeon_audio_write_speaker_allocation(encoder);
+       radeon_audio_write_sad_regs(encoder);
+       radeon_audio_write_latency_fields(encoder, mode);
        radeon_audio_set_dto(encoder, mode->clock);
        radeon_audio_set_vbi_packet(encoder);
        radeon_hdmi_set_color_depth(encoder);
-       radeon_audio_set_mute(encoder, false);
        radeon_audio_update_acr(encoder, mode->clock);
        radeon_audio_set_audio_packet(encoder);
        radeon_audio_select_pin(encoder);
@@ -718,8 +714,7 @@ static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
        if (radeon_audio_set_avi_packet(encoder, mode) < 0)
                return;
 
-       /* enable audio after to setting up hw */
-       radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+       radeon_audio_set_mute(encoder, false);
 }
 
 static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
@@ -729,23 +724,26 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector_atom_dig *dig_connector =
+               radeon_connector->con_priv;
 
        if (!dig || !dig->afmt)
                return;
 
-       /* disable audio prior to setting up hw */
-       dig->afmt->pin = radeon_audio_get_pin(encoder);
-       radeon_audio_enable(rdev, dig->afmt->pin, 0);
-
-       radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
+       radeon_audio_write_speaker_allocation(encoder);
+       radeon_audio_write_sad_regs(encoder);
+       radeon_audio_write_latency_fields(encoder, mode);
+       if (rdev->clock.dp_extclk || ASIC_IS_DCE5(rdev))
+               radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
+       else
+               radeon_audio_set_dto(encoder, dig_connector->dp_clock);
        radeon_audio_set_audio_packet(encoder);
        radeon_audio_select_pin(encoder);
 
        if (radeon_audio_set_avi_packet(encoder, mode) < 0)
                return;
-
-       /* enable audio after to setting up hw */
-       radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
 }
 
 void radeon_audio_mode_set(struct drm_encoder *encoder,
index 63ccb8f..d27e4cc 100644 (file)
@@ -76,7 +76,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
 
 static bool radeon_read_bios(struct radeon_device *rdev)
 {
-       uint8_t __iomem *bios;
+       uint8_t __iomem *bios, val1, val2;
        size_t size;
 
        rdev->bios = NULL;
@@ -86,15 +86,19 @@ static bool radeon_read_bios(struct radeon_device *rdev)
                return false;
        }
 
-       if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+       val1 = readb(&bios[0]);
+       val2 = readb(&bios[1]);
+
+       if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
                pci_unmap_rom(rdev->pdev, bios);
                return false;
        }
-       rdev->bios = kmemdup(bios, size, GFP_KERNEL);
+       rdev->bios = kzalloc(size, GFP_KERNEL);
        if (rdev->bios == NULL) {
                pci_unmap_rom(rdev->pdev, bios);
                return false;
        }
+       memcpy_fromio(rdev->bios, bios, size);
        pci_unmap_rom(rdev->pdev, bios);
        return true;
 }
index c830863..4d0f96c 100644 (file)
@@ -256,11 +256,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
        u32 ring = RADEON_CS_RING_GFX;
        s32 priority = 0;
 
+       INIT_LIST_HEAD(&p->validated);
+
        if (!cs->num_chunks) {
                return 0;
        }
+
        /* get chunks */
-       INIT_LIST_HEAD(&p->validated);
        p->idx = 0;
        p->ib.sa_bo = NULL;
        p->const_ib.sa_bo = NULL;
@@ -715,6 +717,7 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
        struct radeon_cs_chunk *ib_chunk = p->chunk_ib;
        struct radeon_device *rdev = p->rdev;
        uint32_t header;
+       int ret = 0, i;
 
        if (idx >= ib_chunk->length_dw) {
                DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
@@ -743,14 +746,25 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
                break;
        default:
                DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto dump_ib;
        }
        if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) {
                DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n",
                          pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto dump_ib;
        }
        return 0;
+
+dump_ib:
+       for (i = 0; i < ib_chunk->length_dw; i++) {
+               if (i == idx)
+                       printk("\t0x%08x <---\n", radeon_get_ib_value(p, i));
+               else
+                       printk("\t0x%08x\n", radeon_get_ib_value(p, i));
+       }
+       return ret;
 }
 
 /**
index 6b670b0..3a29703 100644 (file)
@@ -179,9 +179,12 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
                    (rdev->pdev->subsystem_vendor == 0x1734) &&
                    (rdev->pdev->subsystem_device == 0x1107))
                        use_bl = false;
+/* Older PPC macs use on-GPU backlight controller */
+#ifndef CONFIG_PPC_PMAC
                /* disable native backlight control on older asics */
                else if (rdev->family < CHIP_R600)
                        use_bl = false;
+#endif
                else
                        use_bl = true;
        }
index d13d1b5..df09ca7 100644 (file)
@@ -1030,37 +1030,59 @@ static inline bool radeon_test_signaled(struct radeon_fence *fence)
        return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags);
 }
 
+struct radeon_wait_cb {
+       struct fence_cb base;
+       struct task_struct *task;
+};
+
+static void
+radeon_fence_wait_cb(struct fence *fence, struct fence_cb *cb)
+{
+       struct radeon_wait_cb *wait =
+               container_of(cb, struct radeon_wait_cb, base);
+
+       wake_up_process(wait->task);
+}
+
 static signed long radeon_fence_default_wait(struct fence *f, bool intr,
                                             signed long t)
 {
        struct radeon_fence *fence = to_radeon_fence(f);
        struct radeon_device *rdev = fence->rdev;
-       bool signaled;
+       struct radeon_wait_cb cb;
 
-       fence_enable_sw_signaling(&fence->base);
+       cb.task = current;
 
-       /*
-        * This function has to return -EDEADLK, but cannot hold
-        * exclusive_lock during the wait because some callers
-        * may already hold it. This means checking needs_reset without
-        * lock, and not fiddling with any gpu internals.
-        *
-        * The callback installed with fence_enable_sw_signaling will
-        * run before our wait_event_*timeout call, so we will see
-        * both the signaled fence and the changes to needs_reset.
-        */
+       if (fence_add_callback(f, &cb.base, radeon_fence_wait_cb))
+               return t;
+
+       while (t > 0) {
+               if (intr)
+                       set_current_state(TASK_INTERRUPTIBLE);
+               else
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+
+               /*
+                * radeon_test_signaled must be called after
+                * set_current_state to prevent a race with wake_up_process
+                */
+               if (radeon_test_signaled(fence))
+                       break;
+
+               if (rdev->needs_reset) {
+                       t = -EDEADLK;
+                       break;
+               }
+
+               t = schedule_timeout(t);
+
+               if (t > 0 && intr && signal_pending(current))
+                       t = -ERESTARTSYS;
+       }
+
+       __set_current_state(TASK_RUNNING);
+       fence_remove_callback(f, &cb.base);
 
-       if (intr)
-               t = wait_event_interruptible_timeout(rdev->fence_queue,
-                       ((signaled = radeon_test_signaled(fence)) ||
-                        rdev->needs_reset), t);
-       else
-               t = wait_event_timeout(rdev->fence_queue,
-                       ((signaled = radeon_test_signaled(fence)) ||
-                        rdev->needs_reset), t);
-
-       if (t > 0 && !signaled)
-               return -EDEADLK;
        return t;
 }
 
index 061eaa9..122eb56 100644 (file)
@@ -153,7 +153,7 @@ void radeon_kfd_device_init(struct radeon_device *rdev)
                        .compute_vmid_bitmap = 0xFF00,
 
                        .first_compute_pipe = 1,
-                       .compute_pipe_count = 8 - 1,
+                       .compute_pipe_count = 4 - 1,
                };
 
                radeon_doorbell_get_kfd_info(rdev,
index a69bd44..572b4db 100644 (file)
@@ -122,7 +122,6 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
        it = interval_tree_iter_first(&rmn->objects, start, end);
        while (it) {
                struct radeon_bo *bo;
-               struct fence *fence;
                int r;
 
                bo = container_of(it, struct radeon_bo, mn_it);
@@ -134,12 +133,10 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
                        continue;
                }
 
-               fence = reservation_object_get_excl(bo->tbo.resv);
-               if (fence) {
-                       r = radeon_fence_wait((struct radeon_fence *)fence, false);
-                       if (r)
-                               DRM_ERROR("(%d) failed to wait for user bo\n", r);
-               }
+               r = reservation_object_wait_timeout_rcu(bo->tbo.resv, true,
+                       false, MAX_SCHEDULE_TIMEOUT);
+               if (r)
+                       DRM_ERROR("(%d) failed to wait for user bo\n", r);
 
                radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU);
                r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
index 43e0994..318165d 100644 (file)
@@ -173,17 +173,6 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
                else
                        rbo->placements[i].lpfn = 0;
        }
-
-       /*
-        * Use two-ended allocation depending on the buffer size to
-        * improve fragmentation quality.
-        * 512kb was measured as the most optimal number.
-        */
-       if (rbo->tbo.mem.size > 512 * 1024) {
-               for (i = 0; i < c; i++) {
-                       rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN;
-               }
-       }
 }
 
 int radeon_bo_create(struct radeon_device *rdev,
index 9f758d3..c1ba83a 100644 (file)
@@ -837,12 +837,8 @@ static void radeon_dpm_thermal_work_handler(struct work_struct *work)
        radeon_pm_compute_clocks(rdev);
 }
 
-static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
-                                                    enum radeon_pm_state_type dpm_state)
+static bool radeon_dpm_single_display(struct radeon_device *rdev)
 {
-       int i;
-       struct radeon_ps *ps;
-       u32 ui_class;
        bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ?
                true : false;
 
@@ -852,6 +848,23 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
                        single_display = false;
        }
 
+       /* 120hz tends to be problematic even if they are under the
+        * vblank limit.
+        */
+       if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120))
+               single_display = false;
+
+       return single_display;
+}
+
+static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
+                                                    enum radeon_pm_state_type dpm_state)
+{
+       int i;
+       struct radeon_ps *ps;
+       u32 ui_class;
+       bool single_display = radeon_dpm_single_display(rdev);
+
        /* certain older asics have a separare 3D performance state,
         * so try that first if the user selected performance
         */
@@ -977,6 +990,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
        struct radeon_ps *ps;
        enum radeon_pm_state_type dpm_state;
        int ret;
+       bool single_display = radeon_dpm_single_display(rdev);
 
        /* if dpm init failed */
        if (!rdev->pm.dpm_enabled)
@@ -1001,6 +1015,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
                /* vce just modifies an existing state so force a change */
                if (ps->vce_active != rdev->pm.dpm.vce_active)
                        goto force;
+               /* user has made a display change (such as timing) */
+               if (rdev->pm.dpm.single_display != single_display)
+                       goto force;
                if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) {
                        /* for pre-BTC and APUs if the num crtcs changed but state is the same,
                         * all we need to do is update the display configuration.
@@ -1063,6 +1080,7 @@ force:
 
        rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
        rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+       rdev->pm.dpm.single_display = single_display;
 
        /* wait for the rings to drain */
        for (i = 0; i < RADEON_NUM_RINGS; i++) {
index 2456f69..8c78723 100644 (file)
@@ -495,7 +495,7 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
        seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw);
        seq_printf(m, "%u dwords in ring\n", count);
 
-       if (!ring->ready)
+       if (!ring->ring)
                return 0;
 
        /* print 8 dw before current rptr as often it's the last executed
index d02aa1d..b292aca 100644 (file)
@@ -598,6 +598,10 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
        enum dma_data_direction direction = write ?
                DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
 
+       /* double check that we don't free the table twice */
+       if (!ttm->sg->sgl)
+               return;
+
        /* free the sg table and pages again */
        dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
 
index d81182a..97a9048 100644 (file)
@@ -694,6 +694,10 @@ int rs600_irq_set(struct radeon_device *rdev)
        WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
        if (ASIC_IS_DCE2(rdev))
                WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
+
+       /* posting read */
+       RREG32(R_000040_GEN_INT_CNTL);
+
        return 0;
 }
 
index 73107fe..a7fb273 100644 (file)
@@ -3162,6 +3162,8 @@ static void si_gpu_init(struct radeon_device *rdev)
        }
 
        WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+       WREG32(SRBM_INT_CNTL, 1);
+       WREG32(SRBM_INT_ACK, 1);
 
        evergreen_fix_pci_max_read_req_size(rdev);
 
@@ -4699,12 +4701,6 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                switch (pkt.type) {
                case RADEON_PACKET_TYPE0:
                        dev_err(rdev->dev, "Packet0 not allowed!\n");
-                       for (i = 0; i < ib->length_dw; i++) {
-                               if (i == idx)
-                                       printk("\t0x%08x <---\n", ib->ptr[i]);
-                               else
-                                       printk("\t0x%08x\n", ib->ptr[i]);
-                       }
                        ret = -EINVAL;
                        break;
                case RADEON_PACKET_TYPE2:
@@ -4736,8 +4732,15 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                        ret = -EINVAL;
                        break;
                }
-               if (ret)
+               if (ret) {
+                       for (i = 0; i < ib->length_dw; i++) {
+                               if (i == idx)
+                                       printk("\t0x%08x <---\n", ib->ptr[i]);
+                               else
+                                       printk("\t0x%08x\n", ib->ptr[i]);
+                       }
                        break;
+               }
        } while (idx < ib->length_dw);
 
        return ret;
@@ -5910,6 +5913,7 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
        tmp = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
        WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, tmp);
        WREG32(GRBM_INT_CNTL, 0);
+       WREG32(SRBM_INT_CNTL, 0);
        if (rdev->num_crtc >= 2) {
                WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
                WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@@ -6199,6 +6203,9 @@ int si_irq_set(struct radeon_device *rdev)
 
        WREG32(CG_THERMAL_INT, thermal_int);
 
+       /* posting read */
+       RREG32(SRBM_STATUS);
+
        return 0;
 }
 
@@ -6609,6 +6616,10 @@ restart_ih:
                                break;
                        }
                        break;
+               case 96:
+                       DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+                       WREG32(SRBM_INT_ACK, 0x1);
+                       break;
                case 124: /* UVD */
                        DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
                        radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
@@ -7119,8 +7130,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
        WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
 
        if (!vclk || !dclk) {
-               /* keep the Bypass mode, put PLL to sleep */
-               WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK);
+               /* keep the Bypass mode */
                return 0;
        }
 
@@ -7136,8 +7146,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
        /* set VCO_MODE to 1 */
        WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_VCO_MODE_MASK, ~UPLL_VCO_MODE_MASK);
 
-       /* toggle UPLL_SLEEP to 1 then back to 0 */
-       WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK);
+       /* disable sleep mode */
        WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_SLEEP_MASK);
 
        /* deassert UPLL_RESET */
index cbd91d2..99a9835 100644 (file)
 #define        CC_SYS_RB_BACKEND_DISABLE                       0xe80
 #define        GC_USER_SYS_RB_BACKEND_DISABLE                  0xe84
 
+#define SRBM_READ_ERROR                                        0xE98
+#define SRBM_INT_CNTL                                  0xEA0
+#define SRBM_INT_ACK                                   0xEA8
+
 #define        SRBM_STATUS2                                    0x0EC4
 #define                DMA_BUSY                                (1 << 5)
 #define                DMA1_BUSY                               (1 << 6)
 
 #define DCCG_AUDIO_DTO0_PHASE                           0x05b0
 #define DCCG_AUDIO_DTO0_MODULE                          0x05b4
-#define DCCG_AUDIO_DTO1_PHASE                           0x05b8
-#define DCCG_AUDIO_DTO1_MODULE                          0x05bc
+#define DCCG_AUDIO_DTO1_PHASE                           0x05c0
+#define DCCG_AUDIO_DTO1_MODULE                          0x05c4
 
 #define AFMT_AUDIO_SRC_CONTROL                          0x713c
 #define                AFMT_AUDIO_SRC_SELECT(x)                (((x) & 7) << 0)
index 1ac7bb8..fbbe78f 100644 (file)
@@ -156,6 +156,9 @@ int vce_v2_0_resume(struct radeon_device *rdev)
        WREG32(VCE_LMI_SWAP_CNTL1, 0);
        WREG32(VCE_LMI_VM_CTRL, 0);
 
+       WREG32(VCE_LMI_VCPU_CACHE_40BIT_BAR, addr >> 8);
+
+       addr &= 0xff;
        size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size);
        WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff);
        WREG32(VCE_VCPU_CACHE_SIZE0, size);
index 3aaa84a..1a52522 100644 (file)
@@ -997,8 +997,10 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
        crtc->state = NULL;
 
        state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (state)
+       if (state) {
                crtc->state = &state->base;
+               crtc->state->crtc = crtc;
+       }
 }
 
 static struct drm_crtc_state *
@@ -1012,6 +1014,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
                return NULL;
 
        copy->base.mode_changed = false;
+       copy->base.active_changed = false;
        copy->base.planes_changed = false;
        copy->base.event = NULL;
 
@@ -1227,9 +1230,6 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
        /* program display mode */
        tegra_dc_set_timings(dc, mode);
 
-       if (dc->soc->supports_border_color)
-               tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
-
        /* interlacing isn't supported yet, so disable it */
        if (dc->soc->supports_interlacing) {
                value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL);
@@ -1252,42 +1252,7 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
 
 static void tegra_crtc_prepare(struct drm_crtc *crtc)
 {
-       struct tegra_dc *dc = to_tegra_dc(crtc);
-       unsigned int syncpt;
-       unsigned long value;
-
        drm_crtc_vblank_off(crtc);
-
-       if (dc->pipe)
-               syncpt = SYNCPT_VBLANK1;
-       else
-               syncpt = SYNCPT_VBLANK0;
-
-       /* initialize display controller */
-       tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
-       tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
-
-       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
-       tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
-
-       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
-               WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
-       tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
-
-       /* initialize timer */
-       value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
-               WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
-       tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
-
-       value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
-               WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
-       tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
-
-       value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
-       tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
-
-       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
-       tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
 }
 
 static void tegra_crtc_commit(struct drm_crtc *crtc)
@@ -1664,6 +1629,8 @@ static int tegra_dc_init(struct host1x_client *client)
        struct tegra_drm *tegra = drm->dev_private;
        struct drm_plane *primary = NULL;
        struct drm_plane *cursor = NULL;
+       unsigned int syncpt;
+       u32 value;
        int err;
 
        if (tegra->domain) {
@@ -1730,6 +1697,40 @@ static int tegra_dc_init(struct host1x_client *client)
                goto cleanup;
        }
 
+       /* initialize display controller */
+       if (dc->pipe)
+               syncpt = SYNCPT_VBLANK1;
+       else
+               syncpt = SYNCPT_VBLANK0;
+
+       tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
+       tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
+
+       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
+       tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
+
+       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
+               WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
+       tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
+
+       /* initialize timer */
+       value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
+               WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
+       tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
+
+       value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
+               WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
+       tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
+
+       value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
+       tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
+
+       value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
+       tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
+
+       if (dc->soc->supports_border_color)
+               tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
+
        return 0;
 
 cleanup:
index 7e06657..7eaaee7 100644 (file)
@@ -851,6 +851,14 @@ static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        h_back_porch = mode->htotal - mode->hsync_end;
        h_front_porch = mode->hsync_start - mode->hdisplay;
 
+       err = clk_set_rate(hdmi->clk, pclk);
+       if (err < 0) {
+               dev_err(hdmi->dev, "failed to set HDMI clock frequency: %d\n",
+                       err);
+       }
+
+       DRM_DEBUG_KMS("HDMI clock rate: %lu Hz\n", clk_get_rate(hdmi->clk));
+
        /* power up sequence */
        value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PLL0);
        value &= ~SOR_PLL_PDBG;
index d395b0b..8d9b7de 100644 (file)
@@ -74,7 +74,7 @@ static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
        pr_err("    has_type: %d\n", man->has_type);
        pr_err("    use_type: %d\n", man->use_type);
        pr_err("    flags: 0x%08X\n", man->flags);
-       pr_err("    gpu_offset: 0x%08lX\n", man->gpu_offset);
+       pr_err("    gpu_offset: 0x%08llX\n", man->gpu_offset);
        pr_err("    size: %llu\n", man->size);
        pr_err("    available_caching: 0x%08X\n", man->available_caching);
        pr_err("    default_caching: 0x%08X\n", man->default_caching);
index 6c6b655..e13b9cb 100644 (file)
@@ -725,32 +725,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                goto out_err1;
        }
 
-       ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM,
-                            (dev_priv->vram_size >> PAGE_SHIFT));
-       if (unlikely(ret != 0)) {
-               DRM_ERROR("Failed initializing memory manager for VRAM.\n");
-               goto out_err2;
-       }
-
-       dev_priv->has_gmr = true;
-       if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
-           refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
-                                        VMW_PL_GMR) != 0) {
-               DRM_INFO("No GMR memory available. "
-                        "Graphics memory resources are very limited.\n");
-               dev_priv->has_gmr = false;
-       }
-
-       if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
-               dev_priv->has_mob = true;
-               if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB,
-                                  VMW_PL_MOB) != 0) {
-                       DRM_INFO("No MOB memory available. "
-                                "3D will be disabled.\n");
-                       dev_priv->has_mob = false;
-               }
-       }
-
        dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start,
                                               dev_priv->mmio_size);
 
@@ -813,6 +787,33 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                goto out_no_fman;
        }
 
+
+       ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM,
+                            (dev_priv->vram_size >> PAGE_SHIFT));
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed initializing memory manager for VRAM.\n");
+               goto out_no_vram;
+       }
+
+       dev_priv->has_gmr = true;
+       if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
+           refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
+                                        VMW_PL_GMR) != 0) {
+               DRM_INFO("No GMR memory available. "
+                        "Graphics memory resources are very limited.\n");
+               dev_priv->has_gmr = false;
+       }
+
+       if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
+               dev_priv->has_mob = true;
+               if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB,
+                                  VMW_PL_MOB) != 0) {
+                       DRM_INFO("No MOB memory available. "
+                                "3D will be disabled.\n");
+                       dev_priv->has_mob = false;
+               }
+       }
+
        vmw_kms_save_vga(dev_priv);
 
        /* Start kms and overlay systems, needs fifo. */
@@ -838,6 +839,12 @@ out_no_fifo:
        vmw_kms_close(dev_priv);
 out_no_kms:
        vmw_kms_restore_vga(dev_priv);
+       if (dev_priv->has_mob)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
+       if (dev_priv->has_gmr)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
+       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+out_no_vram:
        vmw_fence_manager_takedown(dev_priv->fman);
 out_no_fman:
        if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
@@ -853,12 +860,6 @@ out_err4:
        iounmap(dev_priv->mmio_virt);
 out_err3:
        arch_phys_wc_del(dev_priv->mmio_mtrr);
-       if (dev_priv->has_mob)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
-       if (dev_priv->has_gmr)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
-       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
-out_err2:
        (void)ttm_bo_device_release(&dev_priv->bdev);
 out_err1:
        vmw_ttm_global_release(dev_priv);
@@ -887,6 +888,13 @@ static int vmw_driver_unload(struct drm_device *dev)
        }
        vmw_kms_close(dev_priv);
        vmw_overlay_close(dev_priv);
+
+       if (dev_priv->has_mob)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
+       if (dev_priv->has_gmr)
+               (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
+       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+
        vmw_fence_manager_takedown(dev_priv->fman);
        if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
                drm_irq_uninstall(dev_priv->dev);
@@ -898,11 +906,6 @@ static int vmw_driver_unload(struct drm_device *dev)
        ttm_object_device_release(&dev_priv->tdev);
        iounmap(dev_priv->mmio_virt);
        arch_phys_wc_del(dev_priv->mmio_mtrr);
-       if (dev_priv->has_mob)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
-       if (dev_priv->has_gmr)
-               (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
-       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
        (void)ttm_bo_device_release(&dev_priv->bdev);
        vmw_ttm_global_release(dev_priv);
 
@@ -1235,6 +1238,7 @@ static void vmw_remove(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
 
+       pci_disable_device(pdev);
        drm_put_dev(dev);
 }
 
index 33176d0..654c8da 100644 (file)
@@ -890,7 +890,8 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
        ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use MOB buffer.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_no_reloc;
        }
        bo = &vmw_bo->base;
 
@@ -914,7 +915,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
 
 out_no_reloc:
        vmw_dmabuf_unreference(&vmw_bo);
-       vmw_bo_p = NULL;
+       *vmw_bo_p = NULL;
        return ret;
 }
 
@@ -951,7 +952,8 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
        ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use GMR region.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_no_reloc;
        }
        bo = &vmw_bo->base;
 
@@ -974,7 +976,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
 
 out_no_reloc:
        vmw_dmabuf_unreference(&vmw_bo);
-       vmw_bo_p = NULL;
+       *vmw_bo_p = NULL;
        return ret;
 }
 
@@ -2780,13 +2782,11 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
                                  NULL, arg->command_size, arg->throttle_us,
                                  (void __user *)(unsigned long)arg->fence_rep,
                                  NULL);
-
+       ttm_read_unlock(&dev_priv->reservation_sem);
        if (unlikely(ret != 0))
-               goto out_unlock;
+               return ret;
 
        vmw_kms_cursor_post_execbuf(dev_priv);
 
-out_unlock:
-       ttm_read_unlock(&dev_priv->reservation_sem);
-       return ret;
+       return 0;
 }
index 8725b79..07cda8c 100644 (file)
@@ -2033,23 +2033,17 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
        int i;
        struct drm_mode_config *mode_config = &dev->mode_config;
 
-       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
-       if (unlikely(ret != 0))
-               return ret;
-
        if (!arg->num_outputs) {
                struct drm_vmw_rect def_rect = {0, 0, 800, 600};
                vmw_du_update_layout(dev_priv, 1, &def_rect);
-               goto out_unlock;
+               return 0;
        }
 
        rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect);
        rects = kcalloc(arg->num_outputs, sizeof(struct drm_vmw_rect),
                        GFP_KERNEL);
-       if (unlikely(!rects)) {
-               ret = -ENOMEM;
-               goto out_unlock;
-       }
+       if (unlikely(!rects))
+               return -ENOMEM;
 
        user_rects = (void __user *)(unsigned long)arg->rects;
        ret = copy_from_user(rects, user_rects, rects_size);
@@ -2074,7 +2068,5 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
 
 out_free:
        kfree(rects);
-out_unlock:
-       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 }
index b61d6be..3ddfb3d 100644 (file)
@@ -459,6 +459,8 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                clkrate = clk_get_rate(di->clk_ipu);
                div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
+               if (div == 0)
+                       div = 1;
                rate = clkrate / div;
 
                error = rate / (sig->mode.pixelclock / 1000);
index db4fb6e..56ce8c2 100644 (file)
@@ -1872,6 +1872,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
@@ -1926,6 +1927,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 #endif
 #if IS_ENABLED(CONFIG_HID_SAITEK)
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
@@ -1957,6 +1959,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
index 46edb4d..9c47867 100644 (file)
 #define USB_VENDOR_ID_LOGITECH         0x046d
 #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
 #define USB_DEVICE_ID_LOGITECH_T651    0xb00c
+#define USB_DEVICE_ID_LOGITECH_C077    0xc007
 #define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
 #define USB_DEVICE_ID_MS_LK6K          0x00f9
 #define USB_DEVICE_ID_MS_PRESENTER_8K_BT       0x0701
 #define USB_DEVICE_ID_MS_PRESENTER_8K_USB      0x0713
+#define USB_DEVICE_ID_MS_NE7K          0x071d
 #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K      0x0730
 #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500    0x076c
 #define USB_DEVICE_ID_MS_SURFACE_PRO_2   0x0799
 #define USB_VENDOR_ID_SAITEK           0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
 #define USB_DEVICE_ID_SAITEK_PS1000    0x0621
+#define USB_DEVICE_ID_SAITEK_RAT7_OLD  0x0ccb
 #define USB_DEVICE_ID_SAITEK_RAT7      0x0cd7
 #define USB_DEVICE_ID_SAITEK_MMO7      0x0cd0
 
 #define USB_VENDOR_ID_TIVO             0x150a
 #define USB_DEVICE_ID_TIVO_SLIDE_BT    0x1200
 #define USB_DEVICE_ID_TIVO_SLIDE       0x1201
+#define USB_DEVICE_ID_TIVO_SLIDE_PRO   0x1203
 
 #define USB_VENDOR_ID_TOPSEED          0x0766
 #define USB_DEVICE_ID_TOPSEED_CYBERLINK        0x0204
index fbaea6e..af935eb 100644 (file)
@@ -264,6 +264,8 @@ static const struct hid_device_id ms_devices[] = {
                .driver_data = MS_ERGONOMY },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
                .driver_data = MS_ERGONOMY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K),
+               .driver_data = MS_ERGONOMY },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
                .driver_data = MS_ERGONOMY | MS_RDESC },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
index 5632c54..a014f21 100644 (file)
@@ -177,6 +177,8 @@ static int saitek_event(struct hid_device *hdev, struct hid_field *field,
 static const struct hid_device_id saitek_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
                .driver_data = SAITEK_FIX_PS1000 },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD),
+               .driver_data = SAITEK_RELEASE_MODE_RAT7 },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
                .driver_data = SAITEK_RELEASE_MODE_RAT7 },
        { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9),
index 6a58b6c..e54ce10 100644 (file)
@@ -135,8 +135,9 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
 {
        struct hid_sensor_hub_callbacks_list *callback;
        struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+       unsigned long flags;
 
-       spin_lock(&pdata->dyn_callback_lock);
+       spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
        list_for_each_entry(callback, &pdata->dyn_callback_list, list)
                if (callback->usage_id == usage_id &&
                        (collection_index >=
@@ -145,10 +146,11 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
                                callback->hsdev->end_collection_index)) {
                        *priv = callback->priv;
                        *hsdev = callback->hsdev;
-                       spin_unlock(&pdata->dyn_callback_lock);
+                       spin_unlock_irqrestore(&pdata->dyn_callback_lock,
+                                              flags);
                        return callback->usage_callback;
                }
-       spin_unlock(&pdata->dyn_callback_lock);
+       spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
 
        return NULL;
 }
index 31e9d25..1896c01 100644 (file)
@@ -804,7 +804,7 @@ union sixaxis_output_report_01 {
 #define DS4_REPORT_0x81_SIZE 7
 #define SIXAXIS_REPORT_0xF2_SIZE 18
 
-static spinlock_t sony_dev_list_lock;
+static DEFINE_SPINLOCK(sony_dev_list_lock);
 static LIST_HEAD(sony_device_list);
 static DEFINE_IDA(sony_device_id_allocator);
 
@@ -1944,6 +1944,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return -ENOMEM;
        }
 
+       spin_lock_init(&sc->lock);
+
        sc->quirks = quirks;
        hid_set_drvdata(hdev, sc);
        sc->hdev = hdev;
@@ -2147,8 +2149,8 @@ static void __exit sony_exit(void)
 {
        dbg_hid("Sony:%s\n", __func__);
 
-       ida_destroy(&sony_device_id_allocator);
        hid_unregister_driver(&sony_driver);
+       ida_destroy(&sony_device_id_allocator);
 }
 module_init(sony_init);
 module_exit(sony_exit);
index d790d8d..d986969 100644 (file)
@@ -64,6 +64,7 @@ static const struct hid_device_id tivo_devices[] = {
        /* TiVo Slide Bluetooth remote, pairs with a Broadcom dongle */
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, tivo_devices);
index d43e967..36053f3 100644 (file)
@@ -370,7 +370,10 @@ static int i2c_hid_hwreset(struct i2c_client *client)
 static void i2c_hid_get_input(struct i2c_hid *ihid)
 {
        int ret, ret_size;
-       int size = ihid->bufsize;
+       int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
+
+       if (size > ihid->bufsize)
+               size = ihid->bufsize;
 
        ret = i2c_master_recv(ihid->client, ihid->inbuf, size);
        if (ret != size) {
@@ -785,7 +788,7 @@ static int i2c_hid_init_irq(struct i2c_client *client)
        dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq);
 
        ret = request_threaded_irq(client->irq, NULL, i2c_hid_irq,
-                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                       IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                        client->name, ihid);
        if (ret < 0) {
                dev_warn(&client->dev,
index 9be99a6..a821277 100644 (file)
@@ -78,6 +78,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS },
index 1a65079..bbe32d6 100644 (file)
@@ -551,9 +551,13 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
           (features->type == CINTIQ && !(data[1] & 0x40)))
                return 1;
 
-       if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+       if (wacom->shared) {
                wacom->shared->stylus_in_proximity = true;
 
+               if (wacom->shared->touch_down)
+                       return 1;
+       }
+
        /* in Range while exiting */
        if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
                input_report_key(input, BTN_TOUCH, 0);
@@ -778,6 +782,11 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                        input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
                        input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
                        input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
+                       if ((data[2] & 0x07) | data[4] | data[5] | data[6] | data[7] | data[8] | data[9]) {
+                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+                       } else {
+                               input_report_abs(input, ABS_MISC, 0);
+                       }
                } else if (features->type == CINTIQ_HYBRID) {
                        /*
                         * Do not send hardware buttons under Android. They
@@ -1038,27 +1047,28 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
        int i;
-       int current_num_contacts = 0;
+       int current_num_contacts = data[61];
        int contacts_to_send = 0;
        int num_contacts_left = 4; /* maximum contacts per packet */
        int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
        int y_offset = 2;
+       static int contact_with_no_pen_down_count = 0;
 
        if (wacom->features.type == WACOM_27QHDT) {
                current_num_contacts = data[63];
                num_contacts_left = 10;
                byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET;
                y_offset = 0;
-       } else {
-               current_num_contacts = data[61];
        }
 
        /*
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts)
+       if (current_num_contacts) {
                wacom->num_contacts_left = current_num_contacts;
+               contact_with_no_pen_down_count = 0;
+       }
 
        contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
 
@@ -1091,15 +1101,16 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
                                input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
                                input_report_abs(input, ABS_MT_ORIENTATION, w > h);
                        }
+                       contact_with_no_pen_down_count++;
                }
        }
        input_mt_report_pointer_emulation(input, true);
 
        wacom->num_contacts_left -= contacts_to_send;
-       if (wacom->num_contacts_left <= 0)
+       if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-
-       wacom->shared->touch_down = (wacom->num_contacts_left > 0);
+               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       }
        return 1;
 }
 
@@ -1111,6 +1122,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
        int current_num_contacts = data[2];
        int contacts_to_send = 0;
        int x_offset = 0;
+       static int contact_with_no_pen_down_count = 0;
 
        /* MTTPC does not support Height and Width */
        if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
@@ -1120,8 +1132,10 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts)
+       if (current_num_contacts) {
                wacom->num_contacts_left = current_num_contacts;
+               contact_with_no_pen_down_count = 0;
+       }
 
        /* There are at most 5 contacts per packet */
        contacts_to_send = min(5, wacom->num_contacts_left);
@@ -1142,15 +1156,16 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
                        int y = get_unaligned_le16(&data[offset + x_offset + 9]);
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
                }
        }
        input_mt_report_pointer_emulation(input, true);
 
        wacom->num_contacts_left -= contacts_to_send;
-       if (wacom->num_contacts_left < 0)
+       if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-
-       wacom->shared->touch_down = (wacom->num_contacts_left > 0);
+               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       }
        return 1;
 }
 
@@ -1188,29 +1203,25 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
 {
        unsigned char *data = wacom->data;
        struct input_dev *input = wacom->input;
-       bool prox;
+       bool prox = !wacom->shared->stylus_in_proximity;
        int x = 0, y = 0;
 
        if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
                return 0;
 
-       if (!wacom->shared->stylus_in_proximity) {
-               if (len == WACOM_PKGLEN_TPC1FG) {
-                       prox = data[0] & 0x01;
-                       x = get_unaligned_le16(&data[1]);
-                       y = get_unaligned_le16(&data[3]);
-               } else if (len == WACOM_PKGLEN_TPC1FG_B) {
-                       prox = data[2] & 0x01;
-                       x = get_unaligned_le16(&data[3]);
-                       y = get_unaligned_le16(&data[5]);
-               } else {
-                       prox = data[1] & 0x01;
-                       x = le16_to_cpup((__le16 *)&data[2]);
-                       y = le16_to_cpup((__le16 *)&data[4]);
-               }
-       } else
-               /* force touch out when pen is in prox */
-               prox = 0;
+       if (len == WACOM_PKGLEN_TPC1FG) {
+               prox = prox && (data[0] & 0x01);
+               x = get_unaligned_le16(&data[1]);
+               y = get_unaligned_le16(&data[3]);
+       } else if (len == WACOM_PKGLEN_TPC1FG_B) {
+               prox = prox && (data[2] & 0x01);
+               x = get_unaligned_le16(&data[3]);
+               y = get_unaligned_le16(&data[5]);
+       } else {
+               prox = prox && (data[1] & 0x01);
+               x = le16_to_cpup((__le16 *)&data[2]);
+               y = le16_to_cpup((__le16 *)&data[4]);
+       }
 
        if (prox) {
                input_report_abs(input, ABS_X, x);
@@ -1608,6 +1619,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        struct input_dev *pad_input = wacom->pad_input;
        unsigned char *data = wacom->data;
        int i;
+       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1635,6 +1647,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
                        }
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
                }
        }
 
@@ -1644,11 +1657,12 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
        input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
        input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
        return 1;
 }
 
-static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
+static int wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data, int last_touch_count)
 {
        struct wacom_features *features = &wacom->features;
        struct input_dev *input = wacom->input;
@@ -1656,7 +1670,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
        int slot = input_mt_get_slot_by_key(input, data[0]);
 
        if (slot < 0)
-               return;
+               return 0;
 
        touch = touch && !wacom->shared->stylus_in_proximity;
 
@@ -1688,7 +1702,9 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
                input_report_abs(input, ABS_MT_POSITION_Y, y);
                input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
                input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
+               last_touch_count++;
        }
+       return last_touch_count;
 }
 
 static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
@@ -1713,6 +1729,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
        unsigned char *data = wacom->data;
        int count = data[1] & 0x07;
        int i;
+       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1723,12 +1740,15 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
                int msg_id = data[offset];
 
                if (msg_id >= 2 && msg_id <= 17)
-                       wacom_bpt3_touch_msg(wacom, data + offset);
+                       contact_with_no_pen_down_count = 
+                           wacom_bpt3_touch_msg(wacom, data + offset,
+                                                contact_with_no_pen_down_count);
                else if (msg_id == 128)
                        wacom_bpt3_button_msg(wacom, data + offset);
 
        }
        input_mt_report_pointer_emulation(input, true);
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
        return 1;
 }
@@ -1754,6 +1774,9 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
                return 0;
        }
 
+       if (wacom->shared->touch_down)
+               return 0;
+
        prox = (data[1] & 0x20) == 0x20;
 
        /*
@@ -2725,9 +2748,9 @@ static const struct wacom_features wacom_features_0xF6 =
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x32A =
-       { "Wacom Cintiq 27QHD", 119740, 67520, 2047,
-         63, WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Cintiq 27QHD", 119740, 67520, 2047, 63,
+         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0x32B =
        { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63,
          WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
index bce4e9f..6c99ee7 100644 (file)
@@ -147,6 +147,9 @@ static int ads7828_probe(struct i2c_client *client,
                                                    &ads2830_regmap_config);
        }
 
+       if (IS_ERR(data->regmap))
+               return PTR_ERR(data->regmap);
+
        data->cmd_byte = ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
        if (!diff_input)
                data->cmd_byte |= ADS7828_CMD_SD_SE;
index 5f1ff4c..7d7ae97 100644 (file)
 #include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+
 #include <asm/iosf_mbi.h>
+
 #include "i2c-designware-core.h"
 
 #define SEMAPHORE_TIMEOUT      100
 #define PUNIT_SEMAPHORE                0x7
+#define PUNIT_SEMAPHORE_BIT    BIT(0)
+#define PUNIT_SEMAPHORE_ACQUIRE        BIT(1)
 
 static unsigned long acquired;
 
 static int get_sem(struct device *dev, u32 *sem)
 {
-       u32 reg_val;
+       u32 data;
        int ret;
 
        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE,
-                           &reg_val);
+                               &data);
        if (ret) {
                dev_err(dev, "iosf failed to read punit semaphore\n");
                return ret;
        }
 
-       *sem = reg_val & 0x1;
+       *sem = data & PUNIT_SEMAPHORE_BIT;
 
        return 0;
 }
@@ -52,27 +56,29 @@ static void reset_semaphore(struct device *dev)
                return;
        }
 
-       data = data & 0xfffffffe;
+       data &= ~PUNIT_SEMAPHORE_BIT;
        if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
-                                PUNIT_SEMAPHORE, data))
+                               PUNIT_SEMAPHORE, data))
                dev_err(dev, "iosf failed to reset punit semaphore during write\n");
 }
 
-int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
+static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
 {
-       u32 sem = 0;
+       u32 sem;
        int ret;
        unsigned long start, end;
 
+       might_sleep();
+
        if (!dev || !dev->dev)
                return -ENODEV;
 
-       if (!dev->acquire_lock)
+       if (!dev->release_lock)
                return 0;
 
-       /* host driver writes 0x2 to side band semaphore register */
+       /* host driver writes to side band semaphore register */
        ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
-                                PUNIT_SEMAPHORE, 0x2);
+                               PUNIT_SEMAPHORE, PUNIT_SEMAPHORE_ACQUIRE);
        if (ret) {
                dev_err(dev->dev, "iosf punit semaphore request failed\n");
                return ret;
@@ -81,7 +87,7 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
        /* host driver waits for bit 0 to be set in semaphore register */
        start = jiffies;
        end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
-       while (!time_after(jiffies, end)) {
+       do {
                ret = get_sem(dev->dev, &sem);
                if (!ret && sem) {
                        acquired = jiffies;
@@ -91,14 +97,14 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
                }
 
                usleep_range(1000, 2000);
-       }
+       } while (time_before(jiffies, end));
 
        dev_err(dev->dev, "punit semaphore timed out, resetting\n");
        reset_semaphore(dev->dev);
 
        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
-               PUNIT_SEMAPHORE, &sem);
-       if (!ret)
+                               PUNIT_SEMAPHORE, &sem);
+       if (ret)
                dev_err(dev->dev, "iosf failed to read punit semaphore\n");
        else
                dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
@@ -107,9 +113,8 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
 
        return -ETIMEDOUT;
 }
-EXPORT_SYMBOL(baytrail_i2c_acquire);
 
-void baytrail_i2c_release(struct dw_i2c_dev *dev)
+static void baytrail_i2c_release(struct dw_i2c_dev *dev)
 {
        if (!dev || !dev->dev)
                return;
@@ -121,7 +126,6 @@ void baytrail_i2c_release(struct dw_i2c_dev *dev)
        dev_dbg(dev->dev, "punit semaphore held for %ums\n",
                jiffies_to_msecs(jiffies - acquired));
 }
-EXPORT_SYMBOL(baytrail_i2c_release);
 
 int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
 {
@@ -137,7 +141,6 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
                return 0;
 
        status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
-
        if (ACPI_FAILURE(status))
                return 0;
 
@@ -153,7 +156,6 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
 
        return 0;
 }
-EXPORT_SYMBOL(i2c_dw_eval_lock_support);
 
 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
 MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
index 210cf48..edf274c 100644 (file)
@@ -679,9 +679,6 @@ static int i2c_device_remove(struct device *dev)
                status = driver->remove(client);
        }
 
-       if (dev->of_node)
-               irq_dispose_mapping(client->irq);
-
        dev_pm_domain_detach(&client->dev, true);
        return status;
 }
index 1793aea..6eb738c 100644 (file)
@@ -1793,11 +1793,11 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN,
                                         IDETAPE_DSC_RW_MAX);
        printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
-               "%lums tDSC%s\n",
+               "%ums tDSC%s\n",
                drive->name, tape->name, *(u16 *)&tape->caps[14],
                (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
                tape->buffer_size / 1024,
-               tape->best_dsc_rw_freq * 1000 / HZ,
+               jiffies_to_msecs(tape->best_dsc_rw_freq),
                (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
 
        ide_proc_register_driver(drive, tape->driver);
index 1096da3..75c6d21 100644 (file)
@@ -659,7 +659,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = bma180_get_data_reg(data, bit);
                if (ret < 0) {
index 066d0c0..75567fd 100644 (file)
@@ -168,14 +168,14 @@ static const struct {
        int val;
        int val2;
        u8 bw_bits;
-} bmc150_accel_samp_freq_table[] = { {7, 810000, 0x08},
-                                    {15, 630000, 0x09},
-                                    {31, 250000, 0x0A},
-                                    {62, 500000, 0x0B},
-                                    {125, 0, 0x0C},
-                                    {250, 0, 0x0D},
-                                    {500, 0, 0x0E},
-                                    {1000, 0, 0x0F} };
+} bmc150_accel_samp_freq_table[] = { {15, 620000, 0x08},
+                                    {31, 260000, 0x09},
+                                    {62, 500000, 0x0A},
+                                    {125, 0, 0x0B},
+                                    {250, 0, 0x0C},
+                                    {500, 0, 0x0D},
+                                    {1000, 0, 0x0E},
+                                    {2000, 0, 0x0F} };
 
 static const struct {
        int bw_bits;
@@ -840,7 +840,7 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
 }
 
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
-               "7.810000 15.630000 31.250000 62.500000 125 250 500 1000");
+               "15.620000 31.260000 62.50000 125 250 500 1000 2000");
 
 static struct attribute *bmc150_accel_attributes[] = {
        &iio_const_attr_sampling_frequency_available.dev_attr.attr,
@@ -986,7 +986,7 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
        int bit, ret, i = 0;
 
        mutex_lock(&data->mutex);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = i2c_smbus_read_word_data(data->client,
                                               BMC150_ACCEL_AXIS_TO_REG(bit));
index 567de26..1a63795 100644 (file)
@@ -956,7 +956,7 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = kxcjk1013_get_acc_reg(data, bit);
                if (ret < 0) {
index 202daf8..46379b1 100644 (file)
@@ -137,7 +137,8 @@ config AXP288_ADC
 
 config CC10001_ADC
        tristate "Cosmic Circuits 10001 ADC driver"
-       depends on HAS_IOMEM || HAVE_CLK || REGULATOR
+       depends on HAVE_CLK || REGULATOR
+       depends on HAS_IOMEM
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index ff61ae5..8a0eb4a 100644 (file)
@@ -544,7 +544,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
 {
        struct iio_dev *idev = iio_trigger_get_drvdata(trig);
        struct at91_adc_state *st = iio_priv(idev);
-       struct iio_buffer *buffer = idev->buffer;
        struct at91_adc_reg_desc *reg = st->registers;
        u32 status = at91_adc_readl(st, reg->trigger_register);
        int value;
@@ -564,7 +563,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
                at91_adc_writel(st, reg->trigger_register,
                                status | value);
 
-               for_each_set_bit(bit, buffer->scan_mask,
+               for_each_set_bit(bit, idev->active_scan_mask,
                                 st->num_channels) {
                        struct iio_chan_spec const *chan = idev->channels + bit;
                        at91_adc_writel(st, AT91_ADC_CHER,
@@ -579,7 +578,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
                at91_adc_writel(st, reg->trigger_register,
                                status & ~value);
 
-               for_each_set_bit(bit, buffer->scan_mask,
+               for_each_set_bit(bit, idev->active_scan_mask,
                                 st->num_channels) {
                        struct iio_chan_spec const *chan = idev->channels + bit;
                        at91_adc_writel(st, AT91_ADC_CHDR,
index 5167225..b96c636 100644 (file)
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
        }
 
-/* LSB is in nV to eliminate floating point */
-static const u32 rates_to_lsb[] = {1000000, 250000, 62500, 15625};
-
-/*
- *  scales calculated as:
- *  rates_to_lsb[sample_rate] / (1 << pga);
- *  pga is 1 for 0, 2
- */
-
 static const int mcp3422_scales[4][4] = {
-       { 1000000, 250000, 62500, 15625 },
-       { 500000 , 125000, 31250, 7812 },
-       { 250000 , 62500 , 15625, 3906 },
-       { 125000 , 31250 , 7812 , 1953 } };
+       { 1000000, 500000, 250000, 125000 },
+       { 250000 , 125000, 62500 , 31250  },
+       { 62500  , 31250 , 15625 , 7812   },
+       { 15625  , 7812  , 3906  , 1953   } };
 
 /* Constant msleep times for data acquisitions */
 static const int mcp3422_read_times[4] = {
index b9666f2..fabd24e 100644 (file)
@@ -296,7 +296,8 @@ static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
        if (iadc->poll_eoc) {
                ret = iadc_poll_wait_eoc(iadc, wait);
        } else {
-               ret = wait_for_completion_timeout(&iadc->complete, wait);
+               ret = wait_for_completion_timeout(&iadc->complete,
+                       usecs_to_jiffies(wait));
                if (!ret)
                        ret = -ETIMEDOUT;
                else
index 2e5cc44..a0e7161 100644 (file)
@@ -188,12 +188,11 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
 static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
 {
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
-       struct iio_buffer *buffer = indio_dev->buffer;
        unsigned int enb = 0;
        u8 bit;
 
        tiadc_step_config(indio_dev);
-       for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels)
+       for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels)
                enb |= (get_adc_step_bit(adc_dev, bit) << 1);
        adc_dev->buffer_en_ch_steps = enb;
 
index 8ec353c..e63b8e7 100644 (file)
@@ -141,9 +141,13 @@ struct vf610_adc {
        struct regulator *vref;
        struct vf610_adc_feature adc_feature;
 
+       u32 sample_freq_avail[5];
+
        struct completion completion;
 };
 
+static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
+
 #define VF610_ADC_CHAN(_idx, _chan_type) {                     \
        .type = (_chan_type),                                   \
        .indexed = 1,                                           \
@@ -180,35 +184,47 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = {
        /* sentinel */
 };
 
-/*
- * ADC sample frequency, unit is ADCK cycles.
- * ADC clk source is ipg clock, which is the same as bus clock.
- *
- * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
- * SFCAdder: fixed to 6 ADCK cycles
- * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
- * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
- * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
- *
- * By default, enable 12 bit resolution mode, clock source
- * set to ipg clock, So get below frequency group:
- */
-static const u32 vf610_sample_freq_avail[5] =
-{1941176, 559332, 286957, 145374, 73171};
+static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
+{
+       unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
+       int i;
+
+       /*
+        * Calculate ADC sample frequencies
+        * Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
+        * which is the same as bus clock.
+        *
+        * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
+        * SFCAdder: fixed to 6 ADCK cycles
+        * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
+        * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
+        * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
+        */
+       adck_rate = ipg_rate / info->adc_feature.clk_div;
+       for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
+               info->sample_freq_avail[i] =
+                       adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
+}
 
 static inline void vf610_adc_cfg_init(struct vf610_adc *info)
 {
+       struct vf610_adc_feature *adc_feature = &info->adc_feature;
+
        /* set default Configuration for ADC controller */
-       info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET;
-       info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET;
+       adc_feature->clk_sel = VF610_ADCIOC_BUSCLK_SET;
+       adc_feature->vol_ref = VF610_ADCIOC_VR_VREF_SET;
+
+       adc_feature->calibration = true;
+       adc_feature->ovwren = true;
+
+       adc_feature->res_mode = 12;
+       adc_feature->sample_rate = 1;
+       adc_feature->lpm = true;
 
-       info->adc_feature.calibration = true;
-       info->adc_feature.ovwren = true;
+       /* Use a save ADCK which is below 20MHz on all devices */
+       adc_feature->clk_div = 8;
 
-       info->adc_feature.clk_div = 1;
-       info->adc_feature.res_mode = 12;
-       info->adc_feature.sample_rate = 1;
-       info->adc_feature.lpm = true;
+       vf610_adc_calculate_rates(info);
 }
 
 static void vf610_adc_cfg_post_set(struct vf610_adc *info)
@@ -290,12 +306,10 @@ static void vf610_adc_cfg_set(struct vf610_adc *info)
 
        cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
 
-       /* low power configuration */
        cfg_data &= ~VF610_ADC_ADLPC_EN;
        if (adc_feature->lpm)
                cfg_data |= VF610_ADC_ADLPC_EN;
 
-       /* disable high speed */
        cfg_data &= ~VF610_ADC_ADHSC_EN;
 
        writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
@@ -435,10 +449,27 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171");
+static ssize_t vf610_show_samp_freq_avail(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct vf610_adc *info = iio_priv(dev_to_iio_dev(dev));
+       size_t len = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(info->sample_freq_avail); i++)
+               len += scnprintf(buf + len, PAGE_SIZE - len,
+                       "%u ", info->sample_freq_avail[i]);
+
+       /* replace trailing space by newline */
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(vf610_show_samp_freq_avail);
 
 static struct attribute *vf610_attributes[] = {
-       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
        NULL
 };
 
@@ -502,7 +533,7 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
                return IIO_VAL_FRACTIONAL_LOG2;
 
        case IIO_CHAN_INFO_SAMP_FREQ:
-               *val = vf610_sample_freq_avail[info->adc_feature.sample_rate];
+               *val = info->sample_freq_avail[info->adc_feature.sample_rate];
                *val2 = 0;
                return IIO_VAL_INT;
 
@@ -525,9 +556,9 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
        switch (mask) {
                case IIO_CHAN_INFO_SAMP_FREQ:
                        for (i = 0;
-                               i < ARRAY_SIZE(vf610_sample_freq_avail);
+                               i < ARRAY_SIZE(info->sample_freq_avail);
                                i++)
-                               if (val == vf610_sample_freq_avail[i]) {
+                               if (val == info->sample_freq_avail[i]) {
                                        info->adc_feature.sample_rate = i;
                                        vf610_adc_sample_set(info);
                                        return 0;
index 52d7043..55a9008 100644 (file)
@@ -640,6 +640,7 @@ static int ssp_remove(struct spi_device *spi)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int ssp_suspend(struct device *dev)
 {
        int ret;
@@ -688,6 +689,7 @@ static int ssp_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops ssp_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
index f57562a..15c73e2 100644 (file)
@@ -322,7 +322,7 @@ static int ad5686_probe(struct spi_device *spi)
        st = iio_priv(indio_dev);
        spi_set_drvdata(spi, indio_dev);
 
-       st->reg = devm_regulator_get(&spi->dev, "vcc");
+       st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
        if (!IS_ERR(st->reg)) {
                ret = regulator_enable(st->reg);
                if (ret)
index 60451b3..ccf3ea7 100644 (file)
@@ -822,7 +822,7 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
        int bit, ret, i = 0;
 
        mutex_lock(&data->mutex);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = i2c_smbus_read_word_data(data->client,
                                               BMG160_AXIS_TO_REG(bit));
index 623c145..7d79a1a 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/wait.h>
 #include <linux/bitops.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 
 #define DHT11_DATA_VALID_TIME  2000000000  /* 2s in ns */
 
-#define DHT11_EDGES_PREAMBLE 4
+#define DHT11_EDGES_PREAMBLE 2
 #define DHT11_BITS_PER_READ 40
+/*
+ * Note that when reading the sensor actually 84 edges are detected, but
+ * since the last edge is not significant, we only store 83:
+ */
 #define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1)
 
 /* Data transmission timing (nano seconds) */
@@ -57,6 +62,7 @@ struct dht11 {
        int                             irq;
 
        struct completion               completion;
+       struct mutex                    lock;
 
        s64                             timestamp;
        int                             temperature;
@@ -88,7 +94,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
        unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
 
        /* Calculate timestamp resolution */
-       for (i = 0; i < dht11->num_edges; ++i) {
+       for (i = 1; i < dht11->num_edges; ++i) {
                t = dht11->edges[i].ts - dht11->edges[i-1].ts;
                if (t > 0 && t < timeres)
                        timeres = t;
@@ -138,6 +144,27 @@ static int dht11_decode(struct dht11 *dht11, int offset)
        return 0;
 }
 
+/*
+ * IRQ handler called on GPIO edges
+ */
+static irqreturn_t dht11_handle_irq(int irq, void *data)
+{
+       struct iio_dev *iio = data;
+       struct dht11 *dht11 = iio_priv(iio);
+
+       /* TODO: Consider making the handler safe for IRQ sharing */
+       if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
+               dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
+               dht11->edges[dht11->num_edges++].value =
+                                               gpio_get_value(dht11->gpio);
+
+               if (dht11->num_edges >= DHT11_EDGES_PER_READ)
+                       complete(&dht11->completion);
+       }
+
+       return IRQ_HANDLED;
+}
+
 static int dht11_read_raw(struct iio_dev *iio_dev,
                        const struct iio_chan_spec *chan,
                        int *val, int *val2, long m)
@@ -145,6 +172,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
        struct dht11 *dht11 = iio_priv(iio_dev);
        int ret;
 
+       mutex_lock(&dht11->lock);
        if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
                reinit_completion(&dht11->completion);
 
@@ -157,8 +185,17 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                if (ret)
                        goto err;
 
+               ret = request_irq(dht11->irq, dht11_handle_irq,
+                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                 iio_dev->name, iio_dev);
+               if (ret)
+                       goto err;
+
                ret = wait_for_completion_killable_timeout(&dht11->completion,
                                                                 HZ);
+
+               free_irq(dht11->irq, iio_dev);
+
                if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
                        dev_err(&iio_dev->dev,
                                        "Only %d signal edges detected\n",
@@ -185,6 +222,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                ret = -EINVAL;
 err:
        dht11->num_edges = -1;
+       mutex_unlock(&dht11->lock);
        return ret;
 }
 
@@ -193,27 +231,6 @@ static const struct iio_info dht11_iio_info = {
        .read_raw               = dht11_read_raw,
 };
 
-/*
- * IRQ handler called on GPIO edges
-*/
-static irqreturn_t dht11_handle_irq(int irq, void *data)
-{
-       struct iio_dev *iio = data;
-       struct dht11 *dht11 = iio_priv(iio);
-
-       /* TODO: Consider making the handler safe for IRQ sharing */
-       if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
-               dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
-               dht11->edges[dht11->num_edges++].value =
-                                               gpio_get_value(dht11->gpio);
-
-               if (dht11->num_edges >= DHT11_EDGES_PER_READ)
-                       complete(&dht11->completion);
-       }
-
-       return IRQ_HANDLED;
-}
-
 static const struct iio_chan_spec dht11_chan_spec[] = {
        { .type = IIO_TEMP,
                .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), },
@@ -256,11 +273,6 @@ static int dht11_probe(struct platform_device *pdev)
                dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);
                return -EINVAL;
        }
-       ret = devm_request_irq(dev, dht11->irq, dht11_handle_irq,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               pdev->name, iio);
-       if (ret)
-               return ret;
 
        dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
        dht11->num_edges = -1;
@@ -268,6 +280,7 @@ static int dht11_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, iio);
 
        init_completion(&dht11->completion);
+       mutex_init(&dht11->lock);
        iio->name = pdev->name;
        iio->dev.parent = &pdev->dev;
        iio->info = &dht11_iio_info;
index b541646..fa3b809 100644 (file)
@@ -45,12 +45,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan, int *val,
                           int *val2, long mask)
 {
-       struct i2c_client *client = iio_priv(indio_dev);
+       struct i2c_client **client = iio_priv(indio_dev);
        int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = i2c_smbus_read_word_data(client,
+               ret = i2c_smbus_read_word_data(*client,
                                               chan->type == IIO_TEMP ?
                                               SI7020CMD_TEMP_HOLD :
                                               SI7020CMD_RH_HOLD);
@@ -126,7 +126,7 @@ static int si7020_probe(struct i2c_client *client,
        /* Wait the maximum power-up time after software reset. */
        msleep(15);
 
-       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client));
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
        if (!indio_dev)
                return -ENOMEM;
 
index b70873d..fa795dc 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/debugfs.h>
+#include <linux/bitops.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -414,7 +415,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
                mutex_unlock(&indio_dev->mlock);
                if (ret)
                        return ret;
-               val16 = ((val16 & 0xFFF) << 4) >> 4;
+               val16 = sign_extend32(val16, 11);
                *val = val16;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_OFFSET:
index e0017c2..f53e9a8 100644 (file)
@@ -60,7 +60,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
        iio_trigger_set_drvdata(adis->trig, adis);
        ret = iio_trigger_register(adis->trig);
 
-       indio_dev->trig = adis->trig;
+       indio_dev->trig = iio_trigger_get(adis->trig);
        if (ret)
                goto error_free_irq;
 
index f73e60b..ef76afe 100644 (file)
@@ -410,42 +410,46 @@ error_read_raw:
        }
 }
 
-static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr)
+static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val)
 {
-       int result;
+       int result, i;
        u8 d;
 
-       if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM)
-               return -EINVAL;
-       if (fsr == st->chip_config.fsr)
-               return 0;
+       for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) {
+               if (gyro_scale_6050[i] == val) {
+                       d = (i << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
+                       result = inv_mpu6050_write_reg(st,
+                                       st->reg->gyro_config, d);
+                       if (result)
+                               return result;
 
-       d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
-       result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d);
-       if (result)
-               return result;
-       st->chip_config.fsr = fsr;
+                       st->chip_config.fsr = i;
+                       return 0;
+               }
+       }
 
-       return 0;
+       return -EINVAL;
 }
 
-static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs)
+static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val)
 {
-       int result;
+       int result, i;
        u8 d;
 
-       if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM)
-               return -EINVAL;
-       if (fs == st->chip_config.accl_fs)
-               return 0;
+       for (i = 0; i < ARRAY_SIZE(accel_scale); ++i) {
+               if (accel_scale[i] == val) {
+                       d = (i << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
+                       result = inv_mpu6050_write_reg(st,
+                                       st->reg->accl_config, d);
+                       if (result)
+                               return result;
 
-       d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
-       result = inv_mpu6050_write_reg(st, st->reg->accl_config, d);
-       if (result)
-               return result;
-       st->chip_config.accl_fs = fs;
+                       st->chip_config.accl_fs = i;
+                       return 0;
+               }
+       }
 
-       return 0;
+       return -EINVAL;
 }
 
 static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
@@ -471,10 +475,10 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_SCALE:
                switch (chan->type) {
                case IIO_ANGL_VEL:
-                       result = inv_mpu6050_write_fsr(st, val);
+                       result = inv_mpu6050_write_gyro_scale(st, val2);
                        break;
                case IIO_ACCEL:
-                       result = inv_mpu6050_write_accel_fs(st, val);
+                       result = inv_mpu6050_write_accel_scale(st, val2);
                        break;
                default:
                        result = -EINVAL;
@@ -780,7 +784,11 @@ static int inv_mpu_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, indio_dev);
        indio_dev->dev.parent = &client->dev;
-       indio_dev->name = id->name;
+       /* id will be NULL when enumerated via ACPI */
+       if (id)
+               indio_dev->name = (char *)id->name;
+       else
+               indio_dev->name = (char *)dev_name(&client->dev);
        indio_dev->channels = inv_mpu_channels;
        indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
 
index 0cd306a..ba27e27 100644 (file)
 #include <linux/poll.h>
 #include "inv_mpu_iio.h"
 
+static void inv_clear_kfifo(struct inv_mpu6050_state *st)
+{
+       unsigned long flags;
+
+       /* take the spin lock sem to avoid interrupt kick in */
+       spin_lock_irqsave(&st->time_stamp_lock, flags);
+       kfifo_reset(&st->timestamps);
+       spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+}
+
 int inv_reset_fifo(struct iio_dev *indio_dev)
 {
        int result;
@@ -50,6 +60,10 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
                                        INV_MPU6050_BIT_FIFO_RST);
        if (result)
                goto reset_fifo_fail;
+
+       /* clear timestamps fifo */
+       inv_clear_kfifo(st);
+
        /* enable interrupt */
        if (st->chip_config.accl_fifo_enable ||
            st->chip_config.gyro_fifo_enable) {
@@ -83,16 +97,6 @@ reset_fifo_fail:
        return result;
 }
 
-static void inv_clear_kfifo(struct inv_mpu6050_state *st)
-{
-       unsigned long flags;
-
-       /* take the spin lock sem to avoid interrupt kick in */
-       spin_lock_irqsave(&st->time_stamp_lock, flags);
-       kfifo_reset(&st->timestamps);
-       spin_unlock_irqrestore(&st->time_stamp_lock, flags);
-}
-
 /**
  * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt.
  */
@@ -184,7 +188,6 @@ end_session:
 flush_fifo:
        /* Flush HW and SW FIFOs. */
        inv_reset_fifo(indio_dev);
-       inv_clear_kfifo(st);
        mutex_unlock(&indio_dev->mlock);
        iio_trigger_notify_done(indio_dev->trig);
 
index 5cc3692..b3a3637 100644 (file)
@@ -1227,7 +1227,7 @@ static irqreturn_t kmx61_trigger_handler(int irq, void *p)
                base = KMX61_MAG_XOUT_L;
 
        mutex_lock(&data->lock);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = kmx61_read_measurement(data, base, bit);
                if (ret < 0) {
index aaba9d3..4df97f6 100644 (file)
@@ -847,8 +847,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
  * @attr_list: List of IIO device attributes
  *
  * This function frees the memory allocated for each of the IIO device
- * attributes in the list. Note: if you want to reuse the list after calling
- * this function you have to reinitialize it using INIT_LIST_HEAD().
+ * attributes in the list.
  */
 void iio_free_chan_devattr_list(struct list_head *attr_list)
 {
@@ -856,6 +855,7 @@ void iio_free_chan_devattr_list(struct list_head *attr_list)
 
        list_for_each_entry_safe(p, n, attr_list, l) {
                kfree(p->dev_attr.attr.name);
+               list_del(&p->l);
                kfree(p);
        }
 }
@@ -936,6 +936,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
 
        iio_free_chan_devattr_list(&indio_dev->channel_attr_list);
        kfree(indio_dev->chan_attr_group.attrs);
+       indio_dev->chan_attr_group.attrs = NULL;
 }
 
 static void iio_dev_release(struct device *device)
index a4b3970..a99692b 100644 (file)
@@ -500,6 +500,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
 error_free_setup_event_lines:
        iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
        kfree(indio_dev->event_interface);
+       indio_dev->event_interface = NULL;
        return ret;
 }
 
index ae68c64..a224afd 100644 (file)
@@ -73,6 +73,7 @@ config CM36651
 config GP2AP020A00F
        tristate "Sharp GP2AP020A00F Proximity/ALS sensor"
        depends on I2C
+       select REGMAP_I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select IRQ_WORK
@@ -126,6 +127,7 @@ config HID_SENSOR_PROX
 config JSA1212
        tristate "JSA1212 ALS and proximity sensor driver"
        depends on I2C
+       select REGMAP_I2C
        help
         Say Y here if you want to build a IIO driver for JSA1212
         proximity & ALS sensor device.
index 4c7a4c5..a5d6de7 100644 (file)
@@ -18,6 +18,8 @@ config AK8975
 
 config AK09911
        tristate "Asahi Kasei AK09911 3-axis Compass"
+       depends on I2C
+       depends on GPIOLIB
        select AK8975
        help
          Deprecated: AK09911 is now supported by AK8975 driver.
index 74dff4e..89fca3a 100644 (file)
@@ -494,7 +494,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = sx9500_read_proximity(data, &indio_dev->channels[bit],
                                            &val);
index aec7a6a..8c014b5 100644 (file)
@@ -99,6 +99,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
        if (dmasync)
                dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
 
+       /*
+        * If the combination of the addr and size requested for this memory
+        * region causes an integer overflow, return error.
+        */
+       if ((PAGE_ALIGN(addr + size) <= size) ||
+           (PAGE_ALIGN(addr + size) <= addr))
+               return ERR_PTR(-EINVAL);
+
        if (!can_do_mlock())
                return ERR_PTR(-EPERM);
 
index c761971..5904026 100644 (file)
@@ -64,6 +64,14 @@ enum {
 #define GUID_TBL_BLK_NUM_ENTRIES 8
 #define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES)
 
+/* Counters should be saturate once they reach their maximum value */
+#define ASSIGN_32BIT_COUNTER(counter, value) do {\
+       if ((value) > U32_MAX)                   \
+               counter = cpu_to_be32(U32_MAX); \
+       else                                     \
+               counter = cpu_to_be32(value);    \
+} while (0)
+
 struct mlx4_mad_rcv_buf {
        struct ib_grh grh;
        u8 payload[256];
@@ -806,10 +814,14 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
 static void edit_counter(struct mlx4_counter *cnt,
                                        struct ib_pma_portcounters *pma_cnt)
 {
-       pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2));
-       pma_cnt->port_rcv_data  = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2));
-       pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames));
-       pma_cnt->port_rcv_packets  = cpu_to_be32(be64_to_cpu(cnt->rx_frames));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
+                            (be64_to_cpu(cnt->tx_bytes) >> 2));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
+                            (be64_to_cpu(cnt->rx_bytes) >> 2));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
+                            be64_to_cpu(cnt->tx_frames));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
+                            be64_to_cpu(cnt->rx_frames));
 }
 
 static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
index ac6e2b7..b972c0b 100644 (file)
@@ -2697,8 +2697,12 @@ static void handle_bonded_port_state_event(struct work_struct *work)
        spin_lock_bh(&ibdev->iboe.lock);
        for (i = 0; i < MLX4_MAX_PORTS; ++i) {
                struct net_device *curr_netdev = ibdev->iboe.netdevs[i];
+               enum ib_port_state curr_port_state;
 
-               enum ib_port_state curr_port_state =
+               if (!curr_netdev)
+                       continue;
+
+               curr_port_state =
                        (netif_running(curr_netdev) &&
                         netif_carrier_ok(curr_netdev)) ?
                        IB_PORT_ACTIVE : IB_PORT_DOWN;
index 8ff612d..5639325 100644 (file)
@@ -411,9 +411,9 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
 
        input_set_drvdata(input, keypad);
 
-       error = request_threaded_irq(irq, NULL,
-                       tc3589x_keypad_irq, plat->irqtype,
-                       "tc3589x-keypad", keypad);
+       error = request_threaded_irq(irq, NULL, tc3589x_keypad_irq,
+                                    plat->irqtype | IRQF_ONESHOT,
+                                    "tc3589x-keypad", keypad);
        if (error < 0) {
                dev_err(&pdev->dev,
                                "Could not allocate irq %d,error %d\n",
index 59d4dcd..9822877 100644 (file)
@@ -187,6 +187,7 @@ static int mma8450_probe(struct i2c_client *c,
        idev->private           = m;
        idev->input->name       = MMA8450_DRV_NAME;
        idev->input->id.bustype = BUS_I2C;
+       idev->input->dev.parent = &c->dev;
        idev->poll              = mma8450_poll;
        idev->poll_interval     = POLL_INTERVAL;
        idev->poll_interval_max = POLL_INTERVAL_MAX;
index d28726a..27bcdbc 100644 (file)
@@ -1154,10 +1154,28 @@ out:
        mutex_unlock(&alps_mutex);
 }
 
-static void alps_report_bare_ps2_packet(struct input_dev *dev,
+static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
                                        unsigned char packet[],
                                        bool report_buttons)
 {
+       struct alps_data *priv = psmouse->private;
+       struct input_dev *dev;
+
+       /* Figure out which device to use to report the bare packet */
+       if (priv->proto_version == ALPS_PROTO_V2 &&
+           (priv->flags & ALPS_DUALPOINT)) {
+               /* On V2 devices the DualPoint Stick reports bare packets */
+               dev = priv->dev2;
+       } else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) {
+               /* Register dev3 mouse if we received PS/2 packet first time */
+               if (!IS_ERR(priv->dev3))
+                       psmouse_queue_work(psmouse, &priv->dev3_register_work,
+                                          0);
+               return;
+       } else {
+               dev = priv->dev3;
+       }
+
        if (report_buttons)
                alps_report_buttons(dev, NULL,
                                packet[0] & 1, packet[0] & 2, packet[0] & 4);
@@ -1232,8 +1250,8 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
                 * de-synchronization.
                 */
 
-               alps_report_bare_ps2_packet(priv->dev2,
-                                           &psmouse->packet[3], false);
+               alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
+                                           false);
 
                /*
                 * Continue with the standard ALPS protocol handling,
@@ -1289,18 +1307,9 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
         * properly we only do this if the device is fully synchronized.
         */
        if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) {
-
-               /* Register dev3 mouse if we received PS/2 packet first time */
-               if (unlikely(!priv->dev3))
-                       psmouse_queue_work(psmouse,
-                                          &priv->dev3_register_work, 0);
-
                if (psmouse->pktcnt == 3) {
-                       /* Once dev3 mouse device is registered report data */
-                       if (likely(!IS_ERR_OR_NULL(priv->dev3)))
-                               alps_report_bare_ps2_packet(priv->dev3,
-                                                           psmouse->packet,
-                                                           true);
+                       alps_report_bare_ps2_packet(psmouse, psmouse->packet,
+                                                   true);
                        return PSMOUSE_FULL_PACKET;
                }
                return PSMOUSE_GOOD_DATA;
@@ -2281,10 +2290,12 @@ static int alps_set_protocol(struct psmouse *psmouse,
                priv->set_abs_params = alps_set_abs_params_mt;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
-               priv->x_max = 1360;
-               priv->y_max = 660;
                priv->x_bits = 23;
                priv->y_bits = 12;
+
+               if (alps_dolphin_get_device_area(psmouse, priv))
+                       return -EIO;
+
                break;
 
        case ALPS_PROTO_V6:
@@ -2303,9 +2314,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
                priv->set_abs_params = alps_set_abs_params_mt;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
-
-               if (alps_dolphin_get_device_area(psmouse, priv))
-                       return -EIO;
+               priv->x_max = 0xfff;
+               priv->y_max = 0x7ff;
 
                if (priv->fw_ver[1] != 0xba)
                        priv->flags |= ALPS_BUTTONPAD;
@@ -2605,8 +2615,10 @@ int alps_detect(struct psmouse *psmouse, bool set_properties)
                return -ENOMEM;
 
        error = alps_identify(psmouse, priv);
-       if (error)
+       if (error) {
+               kfree(priv);
                return error;
+       }
 
        if (set_properties) {
                psmouse->vendor = "ALPS";
index 77e9d70..1e2291c 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/input/mt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 #include "cyapa.h"
 
 
index ddf5393..5b611dd 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <linux/slab.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 #include <linux/crc-itu-t.h>
 #include "cyapa.h"
 
@@ -1926,7 +1926,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
                                electrodes_tx = cyapa->electrodes_x;
                        max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) &
                                                ~7u) * electrodes_tx;
-               } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+               } else {
                        offset = 2;
                        max_element_cnt = cyapa->electrodes_x +
                                                cyapa->electrodes_y;
index 757f78a..23d2594 100644 (file)
@@ -67,9 +67,6 @@ static void focaltech_reset(struct psmouse *psmouse)
 
 #define FOC_MAX_FINGERS 5
 
-#define FOC_MAX_X 2431
-#define FOC_MAX_Y 1663
-
 /*
  * Current state of a single finger on the touchpad.
  */
@@ -129,9 +126,17 @@ static void focaltech_report_state(struct psmouse *psmouse)
                input_mt_slot(dev, i);
                input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
                if (active) {
-                       input_report_abs(dev, ABS_MT_POSITION_X, finger->x);
+                       unsigned int clamped_x, clamped_y;
+                       /*
+                        * The touchpad might report invalid data, so we clamp
+                        * the resulting values so that we do not confuse
+                        * userspace.
+                        */
+                       clamped_x = clamp(finger->x, 0U, priv->x_max);
+                       clamped_y = clamp(finger->y, 0U, priv->y_max);
+                       input_report_abs(dev, ABS_MT_POSITION_X, clamped_x);
                        input_report_abs(dev, ABS_MT_POSITION_Y,
-                                        FOC_MAX_Y - finger->y);
+                                        priv->y_max - clamped_y);
                }
        }
        input_mt_report_pointer_emulation(dev, true);
@@ -180,16 +185,6 @@ static void focaltech_process_abs_packet(struct psmouse *psmouse,
 
        state->pressed = (packet[0] >> 4) & 1;
 
-       /*
-        * packet[5] contains some kind of tool size in the most
-        * significant nibble. 0xff is a special value (latching) that
-        * signals a large contact area.
-        */
-       if (packet[5] == 0xff) {
-               state->fingers[finger].valid = false;
-               return;
-       }
-
        state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
        state->fingers[finger].y = (packet[3] << 8) | packet[4];
        state->fingers[finger].valid = true;
@@ -381,6 +376,23 @@ static int focaltech_read_size(struct psmouse *psmouse)
 
        return 0;
 }
+
+void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+       /* not supported yet */
+}
+
+static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+       /* not supported yet */
+}
+
+static void focaltech_set_scale(struct psmouse *psmouse,
+                               enum psmouse_scale scale)
+{
+       /* not supported yet */
+}
+
 int focaltech_init(struct psmouse *psmouse)
 {
        struct focaltech_data *priv;
@@ -415,6 +427,14 @@ int focaltech_init(struct psmouse *psmouse)
        psmouse->cleanup = focaltech_reset;
        /* resync is not supported yet */
        psmouse->resync_time = 0;
+       /*
+        * rate/resolution/scale changes are not supported yet, and
+        * the generic implementations of these functions seem to
+        * confuse some touchpads
+        */
+       psmouse->set_resolution = focaltech_set_resolution;
+       psmouse->set_rate = focaltech_set_rate;
+       psmouse->set_scale = focaltech_set_scale;
 
        return 0;
 
index 4ccd01d..8bc6123 100644 (file)
@@ -453,6 +453,17 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
        psmouse->rate = r;
 }
 
+/*
+ * Here we set the mouse scaling.
+ */
+
+static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
+{
+       ps2_command(&psmouse->ps2dev, NULL,
+                   scale == PSMOUSE_SCALE21 ? PSMOUSE_CMD_SETSCALE21 :
+                                              PSMOUSE_CMD_SETSCALE11);
+}
+
 /*
  * psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
  */
@@ -689,6 +700,7 @@ static void psmouse_apply_defaults(struct psmouse *psmouse)
 
        psmouse->set_rate = psmouse_set_rate;
        psmouse->set_resolution = psmouse_set_resolution;
+       psmouse->set_scale = psmouse_set_scale;
        psmouse->poll = psmouse_poll;
        psmouse->protocol_handler = psmouse_process_byte;
        psmouse->pktsize = 3;
@@ -1160,7 +1172,7 @@ static void psmouse_initialize(struct psmouse *psmouse)
        if (psmouse_max_proto != PSMOUSE_PS2) {
                psmouse->set_rate(psmouse, psmouse->rate);
                psmouse->set_resolution(psmouse, psmouse->resolution);
-               ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+               psmouse->set_scale(psmouse, PSMOUSE_SCALE11);
        }
 }
 
index c2ff137..d02e1bd 100644 (file)
@@ -36,6 +36,11 @@ typedef enum {
        PSMOUSE_FULL_PACKET
 } psmouse_ret_t;
 
+enum psmouse_scale {
+       PSMOUSE_SCALE11,
+       PSMOUSE_SCALE21
+};
+
 struct psmouse {
        void *private;
        struct input_dev *dev;
@@ -67,6 +72,7 @@ struct psmouse {
        psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
        void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
        void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution);
+       void (*set_scale)(struct psmouse *psmouse, enum psmouse_scale scale);
 
        int (*reconnect)(struct psmouse *psmouse);
        void (*disconnect)(struct psmouse *psmouse);
index f2cceb6..3b06c8a 100644 (file)
@@ -67,9 +67,6 @@
 #define X_MAX_POSITIVE 8176
 #define Y_MAX_POSITIVE 8176
 
-/* maximum ABS_MT_POSITION displacement (in mm) */
-#define DMAX 10
-
 /*****************************************************************************
  *     Stuff we need even when we do not want native Synaptics support
  ****************************************************************************/
@@ -123,32 +120,46 @@ void synaptics_reset(struct psmouse *psmouse)
 
 static bool cr48_profile_sensor;
 
+#define ANY_BOARD_ID 0
 struct min_max_quirk {
        const char * const *pnp_ids;
+       struct {
+               unsigned long int min, max;
+       } board_id;
        int x_min, x_max, y_min, y_max;
 };
 
 static const struct min_max_quirk min_max_pnpid_table[] = {
        {
                (const char * const []){"LEN0033", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1024, 5052, 2258, 4832
        },
        {
-               (const char * const []){"LEN0035", "LEN0042", NULL},
+               (const char * const []){"LEN0042", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1232, 5710, 1156, 4696
        },
        {
                (const char * const []){"LEN0034", "LEN0036", "LEN0037",
                                        "LEN0039", "LEN2002", "LEN2004",
                                        NULL},
+               {ANY_BOARD_ID, 2961},
                1024, 5112, 2024, 4832
        },
        {
                (const char * const []){"LEN2001", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1024, 5022, 2508, 4832
        },
        {
                (const char * const []){"LEN2006", NULL},
+               {2691, 2691},
+               1024, 5045, 2457, 4832
+       },
+       {
+               (const char * const []){"LEN2006", NULL},
+               {ANY_BOARD_ID, ANY_BOARD_ID},
                1264, 5675, 1171, 4688
        },
        { }
@@ -175,9 +186,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN0041",
        "LEN0042", /* Yoga */
        "LEN0045",
-       "LEN0046",
        "LEN0047",
-       "LEN0048",
        "LEN0049",
        "LEN2000",
        "LEN2001", /* Edge E431 */
@@ -185,7 +194,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN2003",
        "LEN2004", /* L440 */
        "LEN2005",
-       "LEN2006",
+       "LEN2006", /* Edge E440/E540 */
        "LEN2007",
        "LEN2008",
        "LEN2009",
@@ -235,18 +244,39 @@ static int synaptics_model_id(struct psmouse *psmouse)
        return 0;
 }
 
+static int synaptics_more_extended_queries(struct psmouse *psmouse)
+{
+       struct synaptics_data *priv = psmouse->private;
+       unsigned char buf[3];
+
+       if (synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf))
+               return -1;
+
+       priv->ext_cap_10 = (buf[0]<<16) | (buf[1]<<8) | buf[2];
+
+       return 0;
+}
+
 /*
- * Read the board id from the touchpad
+ * Read the board id and the "More Extended Queries" from the touchpad
  * The board id is encoded in the "QUERY MODES" response
  */
-static int synaptics_board_id(struct psmouse *psmouse)
+static int synaptics_query_modes(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char bid[3];
 
+       /* firmwares prior 7.5 have no board_id encoded */
+       if (SYN_ID_FULL(priv->identity) < 0x705)
+               return 0;
+
        if (synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid))
                return -1;
        priv->board_id = ((bid[0] & 0xfc) << 6) | bid[1];
+
+       if (SYN_MEXT_CAP_BIT(bid[0]))
+               return synaptics_more_extended_queries(psmouse);
+
        return 0;
 }
 
@@ -346,7 +376,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char resp[3];
-       int i;
 
        if (SYN_ID_MAJOR(priv->identity) < 4)
                return 0;
@@ -358,17 +387,6 @@ static int synaptics_resolution(struct psmouse *psmouse)
                }
        }
 
-       for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
-               if (psmouse_matches_pnp_id(psmouse,
-                                          min_max_pnpid_table[i].pnp_ids)) {
-                       priv->x_min = min_max_pnpid_table[i].x_min;
-                       priv->x_max = min_max_pnpid_table[i].x_max;
-                       priv->y_min = min_max_pnpid_table[i].y_min;
-                       priv->y_max = min_max_pnpid_table[i].y_max;
-                       return 0;
-               }
-       }
-
        if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
            SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
                if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
@@ -377,23 +395,69 @@ static int synaptics_resolution(struct psmouse *psmouse)
                } else {
                        priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
                        priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
+                       psmouse_info(psmouse,
+                                    "queried max coordinates: x [..%d], y [..%d]\n",
+                                    priv->x_max, priv->y_max);
                }
        }
 
-       if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 &&
-           SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) {
+       if (SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c) &&
+           (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 ||
+            /*
+             * Firmware v8.1 does not report proper number of extended
+             * capabilities, but has been proven to report correct min
+             * coordinates.
+             */
+            SYN_ID_FULL(priv->identity) == 0x801)) {
                if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) {
                        psmouse_warn(psmouse,
                                     "device claims to have min coordinates query, but I'm not able to read it.\n");
                } else {
                        priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
                        priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
+                       psmouse_info(psmouse,
+                                    "queried min coordinates: x [%d..], y [%d..]\n",
+                                    priv->x_min, priv->y_min);
                }
        }
 
        return 0;
 }
 
+/*
+ * Apply quirk(s) if the hardware matches
+ */
+
+static void synaptics_apply_quirks(struct psmouse *psmouse)
+{
+       struct synaptics_data *priv = psmouse->private;
+       int i;
+
+       for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
+               if (!psmouse_matches_pnp_id(psmouse,
+                                           min_max_pnpid_table[i].pnp_ids))
+                       continue;
+
+               if (min_max_pnpid_table[i].board_id.min != ANY_BOARD_ID &&
+                   priv->board_id < min_max_pnpid_table[i].board_id.min)
+                       continue;
+
+               if (min_max_pnpid_table[i].board_id.max != ANY_BOARD_ID &&
+                   priv->board_id > min_max_pnpid_table[i].board_id.max)
+                       continue;
+
+               priv->x_min = min_max_pnpid_table[i].x_min;
+               priv->x_max = min_max_pnpid_table[i].x_max;
+               priv->y_min = min_max_pnpid_table[i].y_min;
+               priv->y_max = min_max_pnpid_table[i].y_max;
+               psmouse_info(psmouse,
+                            "quirked min/max coordinates: x [%d..%d], y [%d..%d]\n",
+                            priv->x_min, priv->x_max,
+                            priv->y_min, priv->y_max);
+               break;
+       }
+}
+
 static int synaptics_query_hardware(struct psmouse *psmouse)
 {
        if (synaptics_identify(psmouse))
@@ -402,13 +466,15 @@ static int synaptics_query_hardware(struct psmouse *psmouse)
                return -1;
        if (synaptics_firmware_id(psmouse))
                return -1;
-       if (synaptics_board_id(psmouse))
+       if (synaptics_query_modes(psmouse))
                return -1;
        if (synaptics_capability(psmouse))
                return -1;
        if (synaptics_resolution(psmouse))
                return -1;
 
+       synaptics_apply_quirks(psmouse);
+
        return 0;
 }
 
@@ -516,18 +582,22 @@ static int synaptics_is_pt_packet(unsigned char *buf)
        return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
 }
 
-static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+static void synaptics_pass_pt_packet(struct psmouse *psmouse,
+                                    struct serio *ptport,
+                                    unsigned char *packet)
 {
+       struct synaptics_data *priv = psmouse->private;
        struct psmouse *child = serio_get_drvdata(ptport);
 
        if (child && child->state == PSMOUSE_ACTIVATED) {
-               serio_interrupt(ptport, packet[1], 0);
+               serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0);
                serio_interrupt(ptport, packet[4], 0);
                serio_interrupt(ptport, packet[5], 0);
                if (child->pktsize == 4)
                        serio_interrupt(ptport, packet[2], 0);
-       } else
+       } else {
                serio_interrupt(ptport, packet[1], 0);
+       }
 }
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
@@ -605,6 +675,18 @@ static void synaptics_parse_agm(const unsigned char buf[],
        }
 }
 
+static void synaptics_parse_ext_buttons(const unsigned char buf[],
+                                       struct synaptics_data *priv,
+                                       struct synaptics_hw_state *hw)
+{
+       unsigned int ext_bits =
+               (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
+       unsigned int ext_mask = GENMASK(ext_bits - 1, 0);
+
+       hw->ext_buttons = buf[4] & ext_mask;
+       hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits;
+}
+
 static bool is_forcepad;
 
 static int synaptics_parse_hw_state(const unsigned char buf[],
@@ -691,28 +773,9 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
                        hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
                }
 
-               if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
+               if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 &&
                    ((buf[0] ^ buf[3]) & 0x02)) {
-                       switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
-                       default:
-                               /*
-                                * if nExtBtn is greater than 8 it should be
-                                * considered invalid and treated as 0
-                                */
-                               break;
-                       case 8:
-                               hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
-                       case 6:
-                               hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
-                       case 4:
-                               hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
-                       case 2:
-                               hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
-                               hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
-                       }
+                       synaptics_parse_ext_buttons(buf, priv, hw);
                }
        } else {
                hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
@@ -774,12 +837,54 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
        }
 }
 
+static void synaptics_report_ext_buttons(struct psmouse *psmouse,
+                                        const struct synaptics_hw_state *hw)
+{
+       struct input_dev *dev = psmouse->dev;
+       struct synaptics_data *priv = psmouse->private;
+       int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
+       char buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+       int i;
+
+       if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+               return;
+
+       /* Bug in FW 8.1, buttons are reported only when ExtBit is 1 */
+       if (SYN_ID_FULL(priv->identity) == 0x801 &&
+           !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
+               return;
+
+       if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) {
+               for (i = 0; i < ext_bits; i++) {
+                       input_report_key(dev, BTN_0 + 2 * i,
+                               hw->ext_buttons & (1 << i));
+                       input_report_key(dev, BTN_1 + 2 * i,
+                               hw->ext_buttons & (1 << (i + ext_bits)));
+               }
+               return;
+       }
+
+       /*
+        * This generation of touchpads has the trackstick buttons
+        * physically wired to the touchpad. Re-route them through
+        * the pass-through interface.
+        */
+       if (!priv->pt_port)
+               return;
+
+       /* The trackstick expects at most 3 buttons */
+       priv->pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons)      |
+                          SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
+                          SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
+
+       synaptics_pass_pt_packet(psmouse, priv->pt_port, buf);
+}
+
 static void synaptics_report_buttons(struct psmouse *psmouse,
                                     const struct synaptics_hw_state *hw)
 {
        struct input_dev *dev = psmouse->dev;
        struct synaptics_data *priv = psmouse->private;
-       int i;
 
        input_report_key(dev, BTN_LEFT, hw->left);
        input_report_key(dev, BTN_RIGHT, hw->right);
@@ -792,8 +897,7 @@ static void synaptics_report_buttons(struct psmouse *psmouse,
                input_report_key(dev, BTN_BACK, hw->down);
        }
 
-       for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
-               input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
+       synaptics_report_ext_buttons(psmouse, hw);
 }
 
 static void synaptics_report_mt_data(struct psmouse *psmouse,
@@ -813,7 +917,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
                pos[i].y = synaptics_invert_y(hw[i]->y);
        }
 
-       input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res);
+       input_mt_assign_slots(dev, slot, pos, nsemi, 0);
 
        for (i = 0; i < nsemi; i++) {
                input_mt_slot(dev, slot[i]);
@@ -1014,7 +1118,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
                if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
                    synaptics_is_pt_packet(psmouse->packet)) {
                        if (priv->pt_port)
-                               synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
+                               synaptics_pass_pt_packet(psmouse, priv->pt_port,
+                                                        psmouse->packet);
                } else
                        synaptics_process_packet(psmouse);
 
@@ -1116,8 +1221,9 @@ static void set_input_params(struct psmouse *psmouse,
                __set_bit(BTN_BACK, dev->keybit);
        }
 
-       for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
-               __set_bit(BTN_0 + i, dev->keybit);
+       if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10))
+               for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
+                       __set_bit(BTN_0 + i, dev->keybit);
 
        __clear_bit(EV_REL, dev->evbit);
        __clear_bit(REL_X, dev->relbit);
@@ -1125,7 +1231,8 @@ static void set_input_params(struct psmouse *psmouse,
 
        if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
                __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
-               if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids))
+               if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
+                   !SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10))
                        __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);
                /* Clickpads report only left button */
                __clear_bit(BTN_RIGHT, dev->keybit);
index aedc329..ee4bd0d 100644 (file)
@@ -22,6 +22,7 @@
 #define SYN_QUE_EXT_CAPAB_0C           0x0c
 #define SYN_QUE_EXT_MAX_COORDS         0x0d
 #define SYN_QUE_EXT_MIN_COORDS         0x0f
+#define SYN_QUE_MEXT_CAPAB_10          0x10
 
 /* synatics modes */
 #define SYN_BIT_ABSOLUTE_MODE          (1 << 7)
@@ -53,6 +54,7 @@
 #define SYN_EXT_CAP_REQUESTS(c)                (((c) & 0x700000) >> 20)
 #define SYN_CAP_MULTI_BUTTON_NO(ec)    (((ec) & 0x00f000) >> 12)
 #define SYN_CAP_PRODUCT_ID(ec)         (((ec) & 0xff0000) >> 16)
+#define SYN_MEXT_CAP_BIT(m)            ((m) & (1 << 1))
 
 /*
  * The following describes response for the 0x0c query.
 #define SYN_CAP_REDUCED_FILTERING(ex0c)        ((ex0c) & 0x000400)
 #define SYN_CAP_IMAGE_SENSOR(ex0c)     ((ex0c) & 0x000800)
 
+/*
+ * The following descibes response for the 0x10 query.
+ *
+ * byte        mask    name                    meaning
+ * ----        ----    -------                 ------------
+ * 1   0x01    ext buttons are stick   buttons exported in the extended
+ *                                     capability are actually meant to be used
+ *                                     by the tracktick (pass-through).
+ * 1   0x02    SecurePad               the touchpad is a SecurePad, so it
+ *                                     contains a built-in fingerprint reader.
+ * 1   0xe0    more ext count          how many more extented queries are
+ *                                     available after this one.
+ * 2   0xff    SecurePad width         the width of the SecurePad fingerprint
+ *                                     reader.
+ * 3   0xff    SecurePad height        the height of the SecurePad fingerprint
+ *                                     reader.
+ */
+#define SYN_CAP_EXT_BUTTONS_STICK(ex10)        ((ex10) & 0x010000)
+#define SYN_CAP_SECUREPAD(ex10)                ((ex10) & 0x020000)
+
+#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01))
+#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02))
+#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04))
+
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)           ((m) & (1 << 7))
 #define SYN_MODE_RATE(m)               ((m) & (1 << 6))
@@ -143,6 +169,7 @@ struct synaptics_data {
        unsigned long int capabilities;         /* Capabilities */
        unsigned long int ext_cap;              /* Extended Capabilities */
        unsigned long int ext_cap_0c;           /* Ext Caps from 0x0c query */
+       unsigned long int ext_cap_10;           /* Ext Caps from 0x10 query */
        unsigned long int identity;             /* Identification */
        unsigned int x_res, y_res;              /* X/Y resolution in units/mm */
        unsigned int x_max, y_max;              /* Max coordinates (from FW) */
@@ -156,6 +183,7 @@ struct synaptics_data {
        bool disable_gesture;                   /* disable gestures */
 
        struct serio *pt_port;                  /* Pass-through serio port */
+       unsigned char pt_buttons;               /* Pass-through buttons */
 
        /*
         * Last received Advanced Gesture Mode (AGM) packet. An AGM packet
index 5891752..6261fd6 100644 (file)
@@ -943,6 +943,7 @@ config TOUCHSCREEN_SUN4I
        tristate "Allwinner sun4i resistive touchscreen controller support"
        depends on ARCH_SUNXI || COMPILE_TEST
        depends on HWMON
+       depends on THERMAL || !THERMAL_OF
        help
          This selects support for the resistive touchscreen controller
          found on Allwinner sunxi SoCs.
index baa0d97..1ae4e54 100644 (file)
@@ -23,6 +23,7 @@ config IOMMU_IO_PGTABLE
 config IOMMU_IO_PGTABLE_LPAE
        bool "ARMv7/v8 Long Descriptor Format"
        select IOMMU_IO_PGTABLE
+       depends on ARM || ARM64 || COMPILE_TEST
        help
          Enable support for the ARM long descriptor pagetable format.
          This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page
@@ -63,6 +64,7 @@ config MSM_IOMMU
        bool "MSM IOMMU Support"
        depends on ARM
        depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST
+       depends on BROKEN
        select IOMMU_API
        help
          Support for the IOMMUs found on certain Qualcomm SOCs.
index fc13dd5..a3adde6 100644 (file)
@@ -1288,10 +1288,13 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
                return 0;
 
        spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
-       if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS)
+       if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS &&
+                       smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
                ret = arm_smmu_iova_to_phys_hard(domain, iova);
-       else
+       } else {
                ret = ops->iova_to_phys(ops, iova);
+       }
+
        spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
 
        return ret;
@@ -1556,7 +1559,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                return -ENODEV;
        }
 
-       if (smmu->version == 1 || (!(id & ID0_ATOSNS) && (id & ID0_S1TS))) {
+       if ((id & ID0_S1TS) && ((smmu->version == 1) || (id & ID0_ATOSNS))) {
                smmu->features |= ARM_SMMU_FEAT_TRANS_OPS;
                dev_notice(smmu->dev, "\taddress translation ops\n");
        }
index 7ce5273..dc14fec 100644 (file)
@@ -1186,8 +1186,15 @@ static const struct iommu_ops exynos_iommu_ops = {
 
 static int __init exynos_iommu_init(void)
 {
+       struct device_node *np;
        int ret;
 
+       np = of_find_matching_node(NULL, sysmmu_of_match);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
+
        lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table",
                                LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL);
        if (!lv2table_kmem_cache) {
index ae4c1a8..2d1e05b 100644 (file)
@@ -1742,9 +1742,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
 
 static void domain_exit(struct dmar_domain *domain)
 {
-       struct dmar_drhd_unit *drhd;
-       struct intel_iommu *iommu;
        struct page *freelist = NULL;
+       int i;
 
        /* Domain 0 is reserved, so dont process it */
        if (!domain)
@@ -1764,8 +1763,8 @@ static void domain_exit(struct dmar_domain *domain)
 
        /* clear attached or cached domains */
        rcu_read_lock();
-       for_each_active_iommu(iommu, drhd)
-               iommu_detach_domain(domain, iommu);
+       for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus)
+               iommu_detach_domain(domain, g_iommus[i]);
        rcu_read_unlock();
 
        dma_free_pagelist(freelist);
index 5a500ed..b610a8d 100644 (file)
@@ -56,7 +56,8 @@
        ((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1))             \
          * (d)->bits_per_level) + (d)->pg_shift)
 
-#define ARM_LPAE_PAGES_PER_PGD(d)      ((d)->pgd_size >> (d)->pg_shift)
+#define ARM_LPAE_PAGES_PER_PGD(d)                                      \
+       DIV_ROUND_UP((d)->pgd_size, 1UL << (d)->pg_shift)
 
 /*
  * Calculate the index at level l used to map virtual address a using the
@@ -66,7 +67,7 @@
        ((l) == ARM_LPAE_START_LVL(d) ? ilog2(ARM_LPAE_PAGES_PER_PGD(d)) : 0)
 
 #define ARM_LPAE_LVL_IDX(a,l,d)                                                \
-       (((a) >> ARM_LPAE_LVL_SHIFT(l,d)) &                             \
+       (((u64)(a) >> ARM_LPAE_LVL_SHIFT(l,d)) &                        \
         ((1 << ((d)->bits_per_level + ARM_LPAE_PGD_IDX(l,d))) - 1))
 
 /* Calculate the block/page mapping size at level l for pagetable in d. */
index 10186ca..bc39bdf 100644 (file)
@@ -851,6 +851,7 @@ static int ipmmu_remove(struct platform_device *pdev)
 
 static const struct of_device_id ipmmu_of_ids[] = {
        { .compatible = "renesas,ipmmu-vmsa", },
+       { }
 };
 
 static struct platform_driver ipmmu_driver = {
index f59f857..a4ba851 100644 (file)
@@ -1376,6 +1376,13 @@ static int __init omap_iommu_init(void)
        struct kmem_cache *p;
        const unsigned long flags = SLAB_HWCACHE_ALIGN;
        size_t align = 1 << 10; /* L2 pagetable alignement */
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, omap_iommu_of_match);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
 
        p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
                              iopte_cachep_ctor);
index 6a8b1ec..9f74fdd 100644 (file)
@@ -1015,8 +1015,15 @@ static struct platform_driver rk_iommu_driver = {
 
 static int __init rk_iommu_init(void)
 {
+       struct device_node *np;
        int ret;
 
+       np = of_find_matching_node(NULL, rk_iommu_dt_ids);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
+
        ret = bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
        if (ret)
                return ret;
index 463c235..4387dae 100644 (file)
@@ -69,6 +69,7 @@ static void __iomem *per_cpu_int_base;
 static void __iomem *main_int_base;
 static struct irq_domain *armada_370_xp_mpic_domain;
 static u32 doorbell_mask_reg;
+static int parent_irq;
 #ifdef CONFIG_PCI_MSI
 static struct irq_domain *armada_370_xp_msi_domain;
 static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
@@ -356,6 +357,7 @@ static int armada_xp_mpic_secondary_init(struct notifier_block *nfb,
 {
        if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
                armada_xp_mpic_smp_cpu_init();
+
        return NOTIFY_OK;
 }
 
@@ -364,6 +366,20 @@ static struct notifier_block armada_370_xp_mpic_cpu_notifier = {
        .priority = 100,
 };
 
+static int mpic_cascaded_secondary_init(struct notifier_block *nfb,
+                                       unsigned long action, void *hcpu)
+{
+       if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
+               enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block mpic_cascaded_cpu_notifier = {
+       .notifier_call = mpic_cascaded_secondary_init,
+       .priority = 100,
+};
+
 #endif /* CONFIG_SMP */
 
 static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
@@ -539,7 +555,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
                                             struct device_node *parent)
 {
        struct resource main_int_res, per_cpu_int_res;
-       int parent_irq, nr_irqs, i;
+       int nr_irqs, i;
        u32 control;
 
        BUG_ON(of_address_to_resource(node, 0, &main_int_res));
@@ -587,6 +603,9 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
                register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier);
 #endif
        } else {
+#ifdef CONFIG_SMP
+               register_cpu_notifier(&mpic_cascaded_cpu_notifier);
+#endif
                irq_set_chained_handler(parent_irq,
                                        armada_370_xp_mpic_handle_cascade_irq);
        }
index d8996bd..9687f8a 100644 (file)
@@ -169,7 +169,7 @@ static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr)
 
 static void its_encode_devid(struct its_cmd_block *cmd, u32 devid)
 {
-       cmd->raw_cmd[0] &= ~(0xffffUL << 32);
+       cmd->raw_cmd[0] &= BIT_ULL(32) - 1;
        cmd->raw_cmd[0] |= ((u64)devid) << 32;
 }
 
@@ -416,13 +416,14 @@ static void its_send_single_command(struct its_node *its,
 {
        struct its_cmd_block *cmd, *sync_cmd, *next_cmd;
        struct its_collection *sync_col;
+       unsigned long flags;
 
-       raw_spin_lock(&its->lock);
+       raw_spin_lock_irqsave(&its->lock, flags);
 
        cmd = its_allocate_entry(its);
        if (!cmd) {             /* We're soooooo screewed... */
                pr_err_ratelimited("ITS can't allocate, dropping command\n");
-               raw_spin_unlock(&its->lock);
+               raw_spin_unlock_irqrestore(&its->lock, flags);
                return;
        }
        sync_col = builder(cmd, desc);
@@ -442,7 +443,7 @@ static void its_send_single_command(struct its_node *its,
 
 post:
        next_cmd = its_post_commands(its);
-       raw_spin_unlock(&its->lock);
+       raw_spin_unlock_irqrestore(&its->lock, flags);
 
        its_wait_for_range_completion(its, cmd, next_cmd);
 }
@@ -799,21 +800,44 @@ static int its_alloc_tables(struct its_node *its)
 {
        int err;
        int i;
-       int psz = PAGE_SIZE;
+       int psz = SZ_64K;
        u64 shr = GITS_BASER_InnerShareable;
+       u64 cache = GITS_BASER_WaWb;
 
        for (i = 0; i < GITS_BASER_NR_REGS; i++) {
                u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
                u64 type = GITS_BASER_TYPE(val);
                u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
+               int order = get_order(psz);
+               int alloc_size;
                u64 tmp;
                void *base;
 
                if (type == GITS_BASER_TYPE_NONE)
                        continue;
 
-               /* We're lazy and only allocate a single page for now */
-               base = (void *)get_zeroed_page(GFP_KERNEL);
+               /*
+                * Allocate as many entries as required to fit the
+                * range of device IDs that the ITS can grok... The ID
+                * space being incredibly sparse, this results in a
+                * massive waste of memory.
+                *
+                * For other tables, only allocate a single page.
+                */
+               if (type == GITS_BASER_TYPE_DEVICE) {
+                       u64 typer = readq_relaxed(its->base + GITS_TYPER);
+                       u32 ids = GITS_TYPER_DEVBITS(typer);
+
+                       order = get_order((1UL << ids) * entry_size);
+                       if (order >= MAX_ORDER) {
+                               order = MAX_ORDER - 1;
+                               pr_warn("%s: Device Table too large, reduce its page order to %u\n",
+                                       its->msi_chip.of_node->full_name, order);
+                       }
+               }
+
+               alloc_size = (1 << order) * PAGE_SIZE;
+               base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
                if (!base) {
                        err = -ENOMEM;
                        goto out_free;
@@ -825,7 +849,7 @@ retry_baser:
                val = (virt_to_phys(base)                                |
                       (type << GITS_BASER_TYPE_SHIFT)                   |
                       ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) |
-                      GITS_BASER_WaWb                                   |
+                      cache                                             |
                       shr                                               |
                       GITS_BASER_VALID);
 
@@ -841,7 +865,7 @@ retry_baser:
                        break;
                }
 
-               val |= (PAGE_SIZE / psz) - 1;
+               val |= (alloc_size / psz) - 1;
 
                writeq_relaxed(val, its->base + GITS_BASER + i * 8);
                tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
@@ -851,9 +875,12 @@ retry_baser:
                         * Shareability didn't stick. Just use
                         * whatever the read reported, which is likely
                         * to be the only thing this redistributor
-                        * supports.
+                        * supports. If that's zero, make it
+                        * non-cacheable as well.
                         */
                        shr = tmp & GITS_BASER_SHAREABILITY_MASK;
+                       if (!shr)
+                               cache = GITS_BASER_nC;
                        goto retry_baser;
                }
 
@@ -882,7 +909,7 @@ retry_baser:
                }
 
                pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
-                       (int)(PAGE_SIZE / entry_size),
+                       (int)(alloc_size / entry_size),
                        its_base_type_string[type],
                        (unsigned long)virt_to_phys(base),
                        psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
@@ -957,16 +984,39 @@ static void its_cpu_init_lpis(void)
        tmp = readq_relaxed(rbase + GICR_PROPBASER);
 
        if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
+               if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) {
+                       /*
+                        * The HW reports non-shareable, we must
+                        * remove the cacheability attributes as
+                        * well.
+                        */
+                       val &= ~(GICR_PROPBASER_SHAREABILITY_MASK |
+                                GICR_PROPBASER_CACHEABILITY_MASK);
+                       val |= GICR_PROPBASER_nC;
+                       writeq_relaxed(val, rbase + GICR_PROPBASER);
+               }
                pr_info_once("GIC: using cache flushing for LPI property table\n");
                gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING;
        }
 
        /* set PENDBASE */
        val = (page_to_phys(pend_page) |
-              GICR_PROPBASER_InnerShareable |
-              GICR_PROPBASER_WaWb);
+              GICR_PENDBASER_InnerShareable |
+              GICR_PENDBASER_WaWb);
 
        writeq_relaxed(val, rbase + GICR_PENDBASER);
+       tmp = readq_relaxed(rbase + GICR_PENDBASER);
+
+       if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) {
+               /*
+                * The HW reports non-shareable, we must remove the
+                * cacheability attributes as well.
+                */
+               val &= ~(GICR_PENDBASER_SHAREABILITY_MASK |
+                        GICR_PENDBASER_CACHEABILITY_MASK);
+               val |= GICR_PENDBASER_nC;
+               writeq_relaxed(val, rbase + GICR_PENDBASER);
+       }
 
        /* Enable LPIs */
        val = readl_relaxed(rbase + GICR_CTLR);
@@ -1003,7 +1053,7 @@ static void its_cpu_init_collection(void)
                         * This ITS wants a linear CPU number.
                         */
                        target = readq_relaxed(gic_data_rdist_rd_base() + GICR_TYPER);
-                       target = GICR_TYPER_CPU_NUMBER(target);
+                       target = GICR_TYPER_CPU_NUMBER(target) << 16;
                }
 
                /* Perform collection mapping */
@@ -1020,8 +1070,9 @@ static void its_cpu_init_collection(void)
 static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
 {
        struct its_device *its_dev = NULL, *tmp;
+       unsigned long flags;
 
-       raw_spin_lock(&its->lock);
+       raw_spin_lock_irqsave(&its->lock, flags);
 
        list_for_each_entry(tmp, &its->its_device_list, entry) {
                if (tmp->device_id == dev_id) {
@@ -1030,7 +1081,7 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
                }
        }
 
-       raw_spin_unlock(&its->lock);
+       raw_spin_unlock_irqrestore(&its->lock, flags);
 
        return its_dev;
 }
@@ -1040,6 +1091,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 {
        struct its_device *dev;
        unsigned long *lpi_map;
+       unsigned long flags;
        void *itt;
        int lpi_base;
        int nr_lpis;
@@ -1056,7 +1108,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        nr_ites = max(2UL, roundup_pow_of_two(nvecs));
        sz = nr_ites * its->ite_size;
        sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
-       itt = kmalloc(sz, GFP_KERNEL);
+       itt = kzalloc(sz, GFP_KERNEL);
        lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
 
        if (!dev || !itt || !lpi_map) {
@@ -1075,9 +1127,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        dev->device_id = dev_id;
        INIT_LIST_HEAD(&dev->entry);
 
-       raw_spin_lock(&its->lock);
+       raw_spin_lock_irqsave(&its->lock, flags);
        list_add(&dev->entry, &its->its_device_list);
-       raw_spin_unlock(&its->lock);
+       raw_spin_unlock_irqrestore(&its->lock, flags);
 
        /* Bind the device to the first possible CPU */
        cpu = cpumask_first(cpu_online_mask);
@@ -1091,9 +1143,11 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 
 static void its_free_device(struct its_device *its_dev)
 {
-       raw_spin_lock(&its_dev->its->lock);
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&its_dev->its->lock, flags);
        list_del(&its_dev->entry);
-       raw_spin_unlock(&its_dev->its->lock);
+       raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
        kfree(its_dev->itt);
        kfree(its_dev);
 }
@@ -1112,31 +1166,69 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
        return 0;
 }
 
+struct its_pci_alias {
+       struct pci_dev  *pdev;
+       u32             dev_id;
+       u32             count;
+};
+
+static int its_pci_msi_vec_count(struct pci_dev *pdev)
+{
+       int msi, msix;
+
+       msi = max(pci_msi_vec_count(pdev), 0);
+       msix = max(pci_msix_vec_count(pdev), 0);
+
+       return max(msi, msix);
+}
+
+static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
+{
+       struct its_pci_alias *dev_alias = data;
+
+       dev_alias->dev_id = alias;
+       if (pdev != dev_alias->pdev)
+               dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev);
+
+       return 0;
+}
+
 static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
                           int nvec, msi_alloc_info_t *info)
 {
        struct pci_dev *pdev;
        struct its_node *its;
-       u32 dev_id;
        struct its_device *its_dev;
+       struct its_pci_alias dev_alias;
 
        if (!dev_is_pci(dev))
                return -EINVAL;
 
        pdev = to_pci_dev(dev);
-       dev_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
+       dev_alias.pdev = pdev;
+       dev_alias.count = nvec;
+
+       pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
        its = domain->parent->host_data;
 
-       its_dev = its_find_device(its, dev_id);
-       if (WARN_ON(its_dev))
-               return -EINVAL;
+       its_dev = its_find_device(its, dev_alias.dev_id);
+       if (its_dev) {
+               /*
+                * We already have seen this ID, probably through
+                * another alias (PCI bridge of some sort). No need to
+                * create the device.
+                */
+               dev_dbg(dev, "Reusing ITT for devID %x\n", dev_alias.dev_id);
+               goto out;
+       }
 
-       its_dev = its_create_device(its, dev_id, nvec);
+       its_dev = its_create_device(its, dev_alias.dev_id, dev_alias.count);
        if (!its_dev)
                return -ENOMEM;
 
-       dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n", nvec, ilog2(nvec));
-
+       dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n",
+               dev_alias.count, ilog2(dev_alias.count));
+out:
        info->scratchpad[0].ptr = its_dev;
        info->scratchpad[1].ptr = dev;
        return 0;
@@ -1255,6 +1347,34 @@ static const struct irq_domain_ops its_domain_ops = {
        .deactivate             = its_irq_domain_deactivate,
 };
 
+static int its_force_quiescent(void __iomem *base)
+{
+       u32 count = 1000000;    /* 1s */
+       u32 val;
+
+       val = readl_relaxed(base + GITS_CTLR);
+       if (val & GITS_CTLR_QUIESCENT)
+               return 0;
+
+       /* Disable the generation of all interrupts to this ITS */
+       val &= ~GITS_CTLR_ENABLE;
+       writel_relaxed(val, base + GITS_CTLR);
+
+       /* Poll GITS_CTLR and wait until ITS becomes quiescent */
+       while (1) {
+               val = readl_relaxed(base + GITS_CTLR);
+               if (val & GITS_CTLR_QUIESCENT)
+                       return 0;
+
+               count--;
+               if (!count)
+                       return -EBUSY;
+
+               cpu_relax();
+               udelay(1);
+       }
+}
+
 static int its_probe(struct device_node *node, struct irq_domain *parent)
 {
        struct resource res;
@@ -1283,6 +1403,13 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
                goto out_unmap;
        }
 
+       err = its_force_quiescent(its_base);
+       if (err) {
+               pr_warn("%s: failed to quiesce, giving up\n",
+                       node->full_name);
+               goto out_unmap;
+       }
+
        pr_info("ITS: %s\n", node->full_name);
 
        its = kzalloc(sizeof(*its), GFP_KERNEL);
@@ -1322,14 +1449,26 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
 
        writeq_relaxed(baser, its->base + GITS_CBASER);
        tmp = readq_relaxed(its->base + GITS_CBASER);
-       writeq_relaxed(0, its->base + GITS_CWRITER);
-       writel_relaxed(1, its->base + GITS_CTLR);
 
-       if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) {
+       if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) {
+               if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) {
+                       /*
+                        * The HW reports non-shareable, we must
+                        * remove the cacheability attributes as
+                        * well.
+                        */
+                       baser &= ~(GITS_CBASER_SHAREABILITY_MASK |
+                                  GITS_CBASER_CACHEABILITY_MASK);
+                       baser |= GITS_CBASER_nC;
+                       writeq_relaxed(baser, its->base + GITS_CBASER);
+               }
                pr_info("ITS: using cache flushing for cmd queue\n");
                its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
        }
 
+       writeq_relaxed(0, its->base + GITS_CWRITER);
+       writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
+
        if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) {
                its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its);
                if (!its->domain) {
@@ -1382,12 +1521,11 @@ static bool gic_rdists_supports_plpis(void)
 
 int its_cpu_init(void)
 {
-       if (!gic_rdists_supports_plpis()) {
-               pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
-               return -ENXIO;
-       }
-
        if (!list_empty(&its_nodes)) {
+               if (!gic_rdists_supports_plpis()) {
+                       pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
+                       return -ENXIO;
+               }
                its_cpu_init_lpis();
                its_cpu_init_collection();
        }
index 1c6dea2..fd8850d 100644 (file)
@@ -466,7 +466,7 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
                tlist |= 1 << (mpidr & 0xf);
 
                cpu = cpumask_next(cpu, mask);
-               if (cpu == nr_cpu_ids)
+               if (cpu >= nr_cpu_ids)
                        goto out;
 
                mpidr = cpu_logical_map(cpu);
index 4634cf7..471e1cd 100644 (file)
@@ -154,23 +154,25 @@ static inline unsigned int gic_irq(struct irq_data *d)
 static void gic_mask_irq(struct irq_data *d)
 {
        u32 mask = 1 << (gic_irq(d) % 32);
+       unsigned long flags;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
        if (gic_arch_extn.irq_mask)
                gic_arch_extn.irq_mask(d);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 static void gic_unmask_irq(struct irq_data *d)
 {
        u32 mask = 1 << (gic_irq(d) % 32);
+       unsigned long flags;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        if (gic_arch_extn.irq_unmask)
                gic_arch_extn.irq_unmask(d);
        writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 static void gic_eoi_irq(struct irq_data *d)
@@ -188,6 +190,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 {
        void __iomem *base = gic_dist_base(d);
        unsigned int gicirq = gic_irq(d);
+       unsigned long flags;
        int ret;
 
        /* Interrupt configuration for SGIs can't be changed */
@@ -199,14 +202,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
                            type != IRQ_TYPE_EDGE_RISING)
                return -EINVAL;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
        if (gic_arch_extn.irq_set_type)
                gic_arch_extn.irq_set_type(d, type);
 
        ret = gic_configure_irq(gicirq, type, base, NULL);
 
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
        return ret;
 }
@@ -227,6 +230,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
        unsigned int cpu, shift = (gic_irq(d) % 4) * 8;
        u32 val, mask, bit;
+       unsigned long flags;
 
        if (!force)
                cpu = cpumask_any_and(mask_val, cpu_online_mask);
@@ -236,12 +240,12 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
                return -EINVAL;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        mask = 0xff << shift;
        bit = gic_cpu_map[cpu] << shift;
        val = readl_relaxed(reg) & ~mask;
        writel_relaxed(val | bit, reg);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
        return IRQ_SET_MASK_OK;
 }
index 3c92780..ff48da6 100644 (file)
@@ -1755,7 +1755,7 @@ init_card(struct hfc_pci *hc)
                enable_hwirq(hc);
                spin_unlock_irqrestore(&hc->lock, flags);
                /* Timeout 80ms */
-               current->state = TASK_UNINTERRUPTIBLE;
+               set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout((80 * HZ) / 1000);
                printk(KERN_INFO "HFC PCI: IRQ %d count %d\n",
                       hc->irq, hc->irqcnt);
index 6a7447c..358a574 100644 (file)
@@ -1609,7 +1609,7 @@ icn_setup(char *line)
        if (ints[0] > 1)
                membase = (unsigned long)ints[2];
        if (str && *str) {
-               strcpy(sid, str);
+               strlcpy(sid, str, sizeof(sid));
                icn_id = sid;
                if ((p = strchr(sid, ','))) {
                        *p++ = 0;
index ee035ec..169172d 100644 (file)
@@ -1,6 +1,6 @@
 config LGUEST
        tristate "Linux hypervisor example code"
-       depends on X86_32 && EVENTFD && TTY
+       depends on X86_32 && EVENTFD && TTY && PCI_DIRECT
        select HVC_DRIVER
        ---help---
          This is a very simple module which allows you to run
index 37de017..74adcd2 100644 (file)
@@ -289,9 +289,16 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
        struct request_queue *q = bdev_get_queue(where->bdev);
        unsigned short logical_block_size = queue_logical_block_size(q);
        sector_t num_sectors;
+       unsigned int uninitialized_var(special_cmd_max_sectors);
 
-       /* Reject unsupported discard requests */
-       if ((rw & REQ_DISCARD) && !blk_queue_discard(q)) {
+       /*
+        * Reject unsupported discard and write same requests.
+        */
+       if (rw & REQ_DISCARD)
+               special_cmd_max_sectors = q->limits.max_discard_sectors;
+       else if (rw & REQ_WRITE_SAME)
+               special_cmd_max_sectors = q->limits.max_write_same_sectors;
+       if ((rw & (REQ_DISCARD | REQ_WRITE_SAME)) && special_cmd_max_sectors == 0) {
                dec_count(io, region, -EOPNOTSUPP);
                return;
        }
@@ -317,7 +324,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                store_io_and_region_in_bio(bio, io, region);
 
                if (rw & REQ_DISCARD) {
-                       num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
+                       num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
                        bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
                        remaining -= num_sectors;
                } else if (rw & REQ_WRITE_SAME) {
@@ -326,7 +333,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                         */
                        dp->get_page(dp, &page, &len, &offset);
                        bio_add_page(bio, page, logical_block_size, offset);
-                       num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining);
+                       num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
                        bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
 
                        offset = 0;
index 8b204ae..f83a0f3 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/log2.h>
 #include <linux/dm-kcopyd.h>
 
+#include "dm.h"
+
 #include "dm-exception-store.h"
 
 #define DM_MSG_PREFIX "snapshots"
@@ -290,6 +292,16 @@ struct origin {
        struct list_head snapshots;
 };
 
+/*
+ * This structure is allocated for each origin target
+ */
+struct dm_origin {
+       struct dm_dev *dev;
+       struct dm_target *ti;
+       unsigned split_boundary;
+       struct list_head hash_list;
+};
+
 /*
  * Size of the hash table for origin volumes. If we make this
  * the size of the minors list then it should be nearly perfect
@@ -297,6 +309,7 @@ struct origin {
 #define ORIGIN_HASH_SIZE 256
 #define ORIGIN_MASK      0xFF
 static struct list_head *_origins;
+static struct list_head *_dm_origins;
 static struct rw_semaphore _origins_lock;
 
 static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done);
@@ -310,12 +323,22 @@ static int init_origin_hash(void)
        _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
                           GFP_KERNEL);
        if (!_origins) {
-               DMERR("unable to allocate memory");
+               DMERR("unable to allocate memory for _origins");
                return -ENOMEM;
        }
-
        for (i = 0; i < ORIGIN_HASH_SIZE; i++)
                INIT_LIST_HEAD(_origins + i);
+
+       _dm_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
+                             GFP_KERNEL);
+       if (!_dm_origins) {
+               DMERR("unable to allocate memory for _dm_origins");
+               kfree(_origins);
+               return -ENOMEM;
+       }
+       for (i = 0; i < ORIGIN_HASH_SIZE; i++)
+               INIT_LIST_HEAD(_dm_origins + i);
+
        init_rwsem(&_origins_lock);
 
        return 0;
@@ -324,6 +347,7 @@ static int init_origin_hash(void)
 static void exit_origin_hash(void)
 {
        kfree(_origins);
+       kfree(_dm_origins);
 }
 
 static unsigned origin_hash(struct block_device *bdev)
@@ -350,6 +374,30 @@ static void __insert_origin(struct origin *o)
        list_add_tail(&o->hash_list, sl);
 }
 
+static struct dm_origin *__lookup_dm_origin(struct block_device *origin)
+{
+       struct list_head *ol;
+       struct dm_origin *o;
+
+       ol = &_dm_origins[origin_hash(origin)];
+       list_for_each_entry (o, ol, hash_list)
+               if (bdev_equal(o->dev->bdev, origin))
+                       return o;
+
+       return NULL;
+}
+
+static void __insert_dm_origin(struct dm_origin *o)
+{
+       struct list_head *sl = &_dm_origins[origin_hash(o->dev->bdev)];
+       list_add_tail(&o->hash_list, sl);
+}
+
+static void __remove_dm_origin(struct dm_origin *o)
+{
+       list_del(&o->hash_list);
+}
+
 /*
  * _origins_lock must be held when calling this function.
  * Returns number of snapshots registered using the supplied cow device, plus:
@@ -1840,9 +1888,40 @@ static int snapshot_preresume(struct dm_target *ti)
 static void snapshot_resume(struct dm_target *ti)
 {
        struct dm_snapshot *s = ti->private;
-       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
+       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL, *snap_merging = NULL;
+       struct dm_origin *o;
+       struct mapped_device *origin_md = NULL;
+       bool must_restart_merging = false;
 
        down_read(&_origins_lock);
+
+       o = __lookup_dm_origin(s->origin->bdev);
+       if (o)
+               origin_md = dm_table_get_md(o->ti->table);
+       if (!origin_md) {
+               (void) __find_snapshots_sharing_cow(s, NULL, NULL, &snap_merging);
+               if (snap_merging)
+                       origin_md = dm_table_get_md(snap_merging->ti->table);
+       }
+       if (origin_md == dm_table_get_md(ti->table))
+               origin_md = NULL;
+       if (origin_md) {
+               if (dm_hold(origin_md))
+                       origin_md = NULL;
+       }
+
+       up_read(&_origins_lock);
+
+       if (origin_md) {
+               dm_internal_suspend_fast(origin_md);
+               if (snap_merging && test_bit(RUNNING_MERGE, &snap_merging->state_bits)) {
+                       must_restart_merging = true;
+                       stop_merge(snap_merging);
+               }
+       }
+
+       down_read(&_origins_lock);
+
        (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
        if (snap_src && snap_dest) {
                down_write(&snap_src->lock);
@@ -1851,8 +1930,16 @@ static void snapshot_resume(struct dm_target *ti)
                up_write(&snap_dest->lock);
                up_write(&snap_src->lock);
        }
+
        up_read(&_origins_lock);
 
+       if (origin_md) {
+               if (must_restart_merging)
+                       start_merge(snap_merging);
+               dm_internal_resume_fast(origin_md);
+               dm_put(origin_md);
+       }
+
        /* Now we have correct chunk size, reregister */
        reregister_snapshot(s);
 
@@ -2133,11 +2220,6 @@ static int origin_write_extent(struct dm_snapshot *merging_snap,
  * Origin: maps a linear range of a device, with hooks for snapshotting.
  */
 
-struct dm_origin {
-       struct dm_dev *dev;
-       unsigned split_boundary;
-};
-
 /*
  * Construct an origin mapping: <dev_path>
  * The context for an origin is merely a 'struct dm_dev *'
@@ -2166,6 +2248,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad_open;
        }
 
+       o->ti = ti;
        ti->private = o;
        ti->num_flush_bios = 1;
 
@@ -2180,6 +2263,7 @@ bad_alloc:
 static void origin_dtr(struct dm_target *ti)
 {
        struct dm_origin *o = ti->private;
+
        dm_put_device(ti, o->dev);
        kfree(o);
 }
@@ -2216,6 +2300,19 @@ static void origin_resume(struct dm_target *ti)
        struct dm_origin *o = ti->private;
 
        o->split_boundary = get_origin_minimum_chunksize(o->dev->bdev);
+
+       down_write(&_origins_lock);
+       __insert_dm_origin(o);
+       up_write(&_origins_lock);
+}
+
+static void origin_postsuspend(struct dm_target *ti)
+{
+       struct dm_origin *o = ti->private;
+
+       down_write(&_origins_lock);
+       __remove_dm_origin(o);
+       up_write(&_origins_lock);
 }
 
 static void origin_status(struct dm_target *ti, status_type_t type,
@@ -2258,12 +2355,13 @@ static int origin_iterate_devices(struct dm_target *ti,
 
 static struct target_type origin_target = {
        .name    = "snapshot-origin",
-       .version = {1, 8, 1},
+       .version = {1, 9, 0},
        .module  = THIS_MODULE,
        .ctr     = origin_ctr,
        .dtr     = origin_dtr,
        .map     = origin_map,
        .resume  = origin_resume,
+       .postsuspend = origin_postsuspend,
        .status  = origin_status,
        .merge   = origin_merge,
        .iterate_devices = origin_iterate_devices,
@@ -2271,7 +2369,7 @@ static struct target_type origin_target = {
 
 static struct target_type snapshot_target = {
        .name    = "snapshot",
-       .version = {1, 12, 0},
+       .version = {1, 13, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2285,7 +2383,7 @@ static struct target_type snapshot_target = {
 
 static struct target_type merge_target = {
        .name    = dm_snapshot_merge_target_name,
-       .version = {1, 2, 0},
+       .version = {1, 3, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
index 654773c..921aafd 100644 (file)
@@ -2358,17 +2358,6 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
 
        case -ENODATA:
-               if (get_pool_mode(tc->pool) == PM_READ_ONLY) {
-                       /*
-                        * This block isn't provisioned, and we have no way
-                        * of doing so.
-                        */
-                       handle_unserviceable_bio(tc->pool, bio);
-                       cell_defer_no_holder(tc, virt_cell);
-                       return DM_MAPIO_SUBMITTED;
-               }
-               /* fall through */
-
        case -EWOULDBLOCK:
                thin_defer_cell(tc, virt_cell);
                return DM_MAPIO_SUBMITTED;
index 73f2880..8001fe9 100644 (file)
@@ -433,7 +433,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
 
        dm_get(md);
        atomic_inc(&md->open_count);
-
 out:
        spin_unlock(&_minor_lock);
 
@@ -442,16 +441,20 @@ out:
 
 static void dm_blk_close(struct gendisk *disk, fmode_t mode)
 {
-       struct mapped_device *md = disk->private_data;
+       struct mapped_device *md;
 
        spin_lock(&_minor_lock);
 
+       md = disk->private_data;
+       if (WARN_ON(!md))
+               goto out;
+
        if (atomic_dec_and_test(&md->open_count) &&
            (test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
                queue_work(deferred_remove_workqueue, &deferred_remove_work);
 
        dm_put(md);
-
+out:
        spin_unlock(&_minor_lock);
 }
 
@@ -2241,7 +2244,6 @@ static void free_dev(struct mapped_device *md)
        int minor = MINOR(disk_devt(md->disk));
 
        unlock_fs(md);
-       bdput(md->bdev);
        destroy_workqueue(md->wq);
 
        if (md->kworker_task)
@@ -2252,19 +2254,22 @@ static void free_dev(struct mapped_device *md)
                mempool_destroy(md->rq_pool);
        if (md->bs)
                bioset_free(md->bs);
-       blk_integrity_unregister(md->disk);
-       del_gendisk(md->disk);
+
        cleanup_srcu_struct(&md->io_barrier);
        free_table_devices(&md->table_devices);
-       free_minor(minor);
+       dm_stats_cleanup(&md->stats);
 
        spin_lock(&_minor_lock);
        md->disk->private_data = NULL;
        spin_unlock(&_minor_lock);
-
+       if (blk_get_integrity(md->disk))
+               blk_integrity_unregister(md->disk);
+       del_gendisk(md->disk);
        put_disk(md->disk);
        blk_cleanup_queue(md->queue);
-       dm_stats_cleanup(&md->stats);
+       bdput(md->bdev);
+       free_minor(minor);
+
        module_put(THIS_MODULE);
        kfree(md);
 }
@@ -2616,6 +2621,19 @@ void dm_get(struct mapped_device *md)
        BUG_ON(test_bit(DMF_FREEING, &md->flags));
 }
 
+int dm_hold(struct mapped_device *md)
+{
+       spin_lock(&_minor_lock);
+       if (test_bit(DMF_FREEING, &md->flags)) {
+               spin_unlock(&_minor_lock);
+               return -EBUSY;
+       }
+       dm_get(md);
+       spin_unlock(&_minor_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dm_hold);
+
 const char *dm_device_name(struct mapped_device *md)
 {
        return md->name;
@@ -2629,8 +2647,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
 
        might_sleep();
 
-       spin_lock(&_minor_lock);
        map = dm_get_live_table(md, &srcu_idx);
+
+       spin_lock(&_minor_lock);
        idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
        set_bit(DMF_FREEING, &md->flags);
        spin_unlock(&_minor_lock);
@@ -2638,10 +2657,16 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
        if (dm_request_based(md))
                flush_kthread_worker(&md->kworker);
 
+       /*
+        * Take suspend_lock so that presuspend and postsuspend methods
+        * do not race with internal suspend.
+        */
+       mutex_lock(&md->suspend_lock);
        if (!dm_suspended_md(md)) {
                dm_table_presuspend_targets(map);
                dm_table_postsuspend_targets(map);
        }
+       mutex_unlock(&md->suspend_lock);
 
        /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
        dm_put_live_table(md, srcu_idx);
@@ -3115,6 +3140,7 @@ void dm_internal_suspend_fast(struct mapped_device *md)
        flush_workqueue(md->wq);
        dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
 }
+EXPORT_SYMBOL_GPL(dm_internal_suspend_fast);
 
 void dm_internal_resume_fast(struct mapped_device *md)
 {
@@ -3126,6 +3152,7 @@ void dm_internal_resume_fast(struct mapped_device *md)
 done:
        mutex_unlock(&md->suspend_lock);
 }
+EXPORT_SYMBOL_GPL(dm_internal_resume_fast);
 
 /*-----------------------------------------------------------------
  * Event notification.
index c8d2bac..717daad 100644 (file)
@@ -2555,7 +2555,7 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
        return err ? err : len;
 }
 static struct rdev_sysfs_entry rdev_state =
-__ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store);
+__ATTR_PREALLOC(state, S_IRUGO|S_IWUSR, state_show, state_store);
 
 static ssize_t
 errors_show(struct md_rdev *rdev, char *page)
@@ -3638,7 +3638,8 @@ resync_start_store(struct mddev *mddev, const char *buf, size_t len)
        return err ?: len;
 }
 static struct md_sysfs_entry md_resync_start =
-__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);
+__ATTR_PREALLOC(resync_start, S_IRUGO|S_IWUSR,
+               resync_start_show, resync_start_store);
 
 /*
  * The array state can be:
@@ -3851,7 +3852,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
        return err ?: len;
 }
 static struct md_sysfs_entry md_array_state =
-__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
+__ATTR_PREALLOC(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
 
 static ssize_t
 max_corrected_read_errors_show(struct mddev *mddev, char *page) {
@@ -4101,7 +4102,7 @@ out_unlock:
 }
 
 static struct md_sysfs_entry md_metadata =
-__ATTR(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
+__ATTR_PREALLOC(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
 
 static ssize_t
 action_show(struct mddev *mddev, char *page)
@@ -4189,7 +4190,7 @@ action_store(struct mddev *mddev, const char *page, size_t len)
 }
 
 static struct md_sysfs_entry md_scan_mode =
-__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
+__ATTR_PREALLOC(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
 
 static ssize_t
 last_sync_action_show(struct mddev *mddev, char *page)
@@ -4335,7 +4336,8 @@ sync_completed_show(struct mddev *mddev, char *page)
        return sprintf(page, "%llu / %llu\n", resync, max_sectors);
 }
 
-static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
+static struct md_sysfs_entry md_sync_completed =
+       __ATTR_PREALLOC(sync_completed, S_IRUGO, sync_completed_show, NULL);
 
 static ssize_t
 min_sync_show(struct mddev *mddev, char *page)
@@ -5078,7 +5080,8 @@ int md_run(struct mddev *mddev)
        }
        if (err) {
                mddev_detach(mddev);
-               pers->free(mddev, mddev->private);
+               if (mddev->private)
+                       pers->free(mddev, mddev->private);
                module_put(pers->owner);
                bitmap_destroy(mddev);
                return err;
index a13f738..3ed9f42 100644 (file)
@@ -467,8 +467,6 @@ static int raid0_run(struct mddev *mddev)
        dump_zones(mddev);
 
        ret = md_integrity_register(mddev);
-       if (ret)
-               raid0_free(mddev, conf);
 
        return ret;
 }
index 4153da5..d34e238 100644 (file)
@@ -560,7 +560,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                if (test_bit(WriteMostly, &rdev->flags)) {
                        /* Don't balance among write-mostly, just
                         * use the first as a last resort */
-                       if (best_disk < 0) {
+                       if (best_dist_disk < 0) {
                                if (is_badblock(rdev, this_sector, sectors,
                                                &first_bad, &bad_sectors)) {
                                        if (first_bad < this_sector)
@@ -569,7 +569,8 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                                        best_good_sectors = first_bad - this_sector;
                                } else
                                        best_good_sectors = sectors;
-                               best_disk = disk;
+                               best_dist_disk = disk;
+                               best_pending_disk = disk;
                        }
                        continue;
                }
index e75d48c..cd2f96b 100644 (file)
@@ -5121,12 +5121,17 @@ static inline sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int
                schedule_timeout_uninterruptible(1);
        }
        /* Need to check if array will still be degraded after recovery/resync
-        * We don't need to check the 'failed' flag as when that gets set,
-        * recovery aborts.
+        * Note in case of > 1 drive failures it's possible we're rebuilding
+        * one drive while leaving another faulty drive in array.
         */
-       for (i = 0; i < conf->raid_disks; i++)
-               if (conf->disks[i].rdev == NULL)
+       rcu_read_lock();
+       for (i = 0; i < conf->raid_disks; i++) {
+               struct md_rdev *rdev = ACCESS_ONCE(conf->disks[i].rdev);
+
+               if (rdev == NULL || test_bit(Faulty, &rdev->flags))
                        still_degraded = 1;
+       }
+       rcu_read_unlock();
 
        bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
 
index f38ec42..5615522 100644 (file)
@@ -739,7 +739,7 @@ static int __init kempld_init(void)
                for (id = kempld_dmi_table;
                     id->matches[0].slot != DMI_NONE; id++)
                        if (strstr(id->ident, force_device_id))
-                               if (id->callback && id->callback(id))
+                               if (id->callback && !id->callback(id))
                                        break;
                if (id->matches[0].slot == DMI_NONE)
                        return -ENODEV;
index ede5024..dbd907d 100644 (file)
@@ -196,18 +196,27 @@ EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register);
 int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
 {
        u16 value;
+       u8 *buf;
+       int ret;
 
        if (!data)
                return -EINVAL;
-       *data = 0;
+
+       buf = kzalloc(sizeof(u8), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT;
        value = swab16(addr);
 
-       return usb_control_msg(ucr->pusb_dev,
+       ret = usb_control_msg(ucr->pusb_dev,
                        usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, 0, data, 1, 100);
+                       value, 0, buf, 1, 100);
+       *data = *buf;
+
+       kfree(buf);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register);
 
@@ -288,18 +297,27 @@ static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status)
 int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
 {
        int ret;
+       u16 *buf;
 
        if (!status)
                return -EINVAL;
 
-       if (polling_pipe == 0)
+       if (polling_pipe == 0) {
+               buf = kzalloc(sizeof(u16), GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+
                ret = usb_control_msg(ucr->pusb_dev,
                                usb_rcvctrlpipe(ucr->pusb_dev, 0),
                                RTSX_USB_REQ_POLL,
                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               0, 0, status, 2, 100);
-       else
+                               0, 0, buf, 2, 100);
+               *status = *buf;
+
+               kfree(buf);
+       } else {
                ret = rtsx_usb_get_status_with_bulk(ucr, status);
+       }
 
        /* usb_control_msg may return positive when success */
        if (ret < 0)
index 9306219..6ad049a 100644 (file)
@@ -341,6 +341,8 @@ void mei_stop(struct mei_device *dev)
 
        dev->dev_state = MEI_DEV_POWER_DOWN;
        mei_reset(dev);
+       /* move device to disabled state unconditionally */
+       dev->dev_state = MEI_DEV_DISABLED;
 
        mutex_unlock(&dev->device_lock);
 
index e9f1d8d..c53f14a 100644 (file)
@@ -124,7 +124,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
                    PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) {
                        ret = PTR_ERR(pwrseq->reset_gpios[i]);
 
-                       while (--i)
+                       while (i--)
                                gpiod_put(pwrseq->reset_gpios[i]);
 
                        goto clk_put;
index 5b76a17..5897d8d 100644 (file)
@@ -526,6 +526,7 @@ config MTD_NAND_SUNXI
 
 config MTD_NAND_HISI504
        tristate "Support for NAND controller on Hisilicon SoC Hip04"
+       depends on HAS_DMA
        help
          Enables support for NAND controller on Hisilicon SoC Hip04.
 
index 96b0b1d..10b1f7a 100644 (file)
@@ -480,6 +480,42 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
        nand_writel(info, NDCR, ndcr | int_mask);
 }
 
+static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
+{
+       if (info->ecc_bch) {
+               int timeout;
+
+               /*
+                * According to the datasheet, when reading from NDDB
+                * with BCH enabled, after each 32 bytes reads, we
+                * have to make sure that the NDSR.RDDREQ bit is set.
+                *
+                * Drain the FIFO 8 32 bits reads at a time, and skip
+                * the polling on the last read.
+                */
+               while (len > 8) {
+                       __raw_readsl(info->mmio_base + NDDB, data, 8);
+
+                       for (timeout = 0;
+                            !(nand_readl(info, NDSR) & NDSR_RDDREQ);
+                            timeout++) {
+                               if (timeout >= 5) {
+                                       dev_err(&info->pdev->dev,
+                                               "Timeout on RDDREQ while draining the FIFO\n");
+                                       return;
+                               }
+
+                               mdelay(1);
+                       }
+
+                       data += 32;
+                       len -= 8;
+               }
+       }
+
+       __raw_readsl(info->mmio_base + NDDB, data, len);
+}
+
 static void handle_data_pio(struct pxa3xx_nand_info *info)
 {
        unsigned int do_bytes = min(info->data_size, info->chunk_size);
@@ -496,14 +532,14 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
                                      DIV_ROUND_UP(info->oob_size, 4));
                break;
        case STATE_PIO_READING:
-               __raw_readsl(info->mmio_base + NDDB,
-                            info->data_buff + info->data_buff_pos,
-                            DIV_ROUND_UP(do_bytes, 4));
+               drain_fifo(info,
+                          info->data_buff + info->data_buff_pos,
+                          DIV_ROUND_UP(do_bytes, 4));
 
                if (info->oob_size > 0)
-                       __raw_readsl(info->mmio_base + NDDB,
-                                    info->oob_buff + info->oob_buff_pos,
-                                    DIV_ROUND_UP(info->oob_size, 4));
+                       drain_fifo(info,
+                                  info->oob_buff + info->oob_buff_pos,
+                                  DIV_ROUND_UP(info->oob_size, 4));
                break;
        default:
                dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
@@ -1572,6 +1608,8 @@ static int alloc_nand_resource(struct platform_device *pdev)
        int ret, irq, cs;
 
        pdata = dev_get_platdata(&pdev->dev);
+       if (pdata->num_cs <= 0)
+               return -ENODEV;
        info = devm_kzalloc(&pdev->dev, sizeof(*info) + (sizeof(*mtd) +
                            sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
        if (!info)
index da4c792..16e34b3 100644 (file)
@@ -425,9 +425,10 @@ retry:
                                        ubi_warn(ubi, "corrupted VID header at PEB %d, LEB %d:%d",
                                                 pnum, vol_id, lnum);
                                        err = -EBADMSG;
-                               } else
+                               } else {
                                        err = -EINVAL;
                                        ubi_ro_mode(ubi);
+                               }
                        }
                        goto out_free;
                } else if (err == UBI_IO_BITFLIPS)
index 84673eb..df51d60 100644 (file)
@@ -157,7 +157,7 @@ config IPVLAN
       making it transparent to the connected L2 switch.
 
       Ipvlan devices can be added using the "ip" command from the
-      iproute2 package starting with the iproute2-X.Y.ZZ release:
+      iproute2 package starting with the iproute2-3.19 release:
 
       "ip link add link <main-dev> [ NAME ] type ipvlan"
 
index 4ce6ca5..dc6b78e 100644 (file)
@@ -40,7 +40,7 @@ config DEV_APPLETALK
 
 config LTPC
        tristate "Apple/Farallon LocalTalk PC support"
-       depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API
+       depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API && VIRT_TO_BUS
        help
          This allows you to use the AppleTalk PC card to connect to LocalTalk
          networks. The card is also known as the Farallon PhoneNet PC card.
index b979c26..089a402 100644 (file)
@@ -3850,7 +3850,8 @@ static inline int bond_slave_override(struct bonding *bond,
        /* Find out if any slaves have the same mapping as this skb. */
        bond_for_each_slave_rcu(bond, slave, iter) {
                if (slave->queue_id == skb->queue_mapping) {
-                       if (bond_slave_can_tx(slave)) {
+                       if (bond_slave_is_up(slave) &&
+                           slave->link == BOND_LINK_UP) {
                                bond_dev_queue_xmit(bond, skb, slave->dev);
                                return 0;
                        }
index 98d73aa..58808f6 100644 (file)
@@ -131,7 +131,7 @@ config CAN_RCAR
 
 config CAN_XILINXCAN
        tristate "Xilinx CAN"
-       depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
+       depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST
        depends on COMMON_CLK && HAS_IOMEM
        ---help---
          Xilinx CAN driver. This driver supports both soft AXI CAN IP and
index 3c82e02..b0f6924 100644 (file)
@@ -579,6 +579,10 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
 
@@ -603,6 +607,10 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
 
index 80c46ad..ad0a7e8 100644 (file)
@@ -592,13 +592,12 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
                rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ?
                           CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
                new_state = max(tx_state, rx_state);
-       } else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE)) {
+       } else {
                __flexcan_get_berr_counter(dev, &bec);
-               new_state = CAN_STATE_ERROR_PASSIVE;
+               new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ?
+                           CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF;
                rx_state = bec.rxerr >= bec.txerr ? new_state : 0;
                tx_state = bec.rxerr <= bec.txerr ? new_state : 0;
-       } else {
-               new_state = CAN_STATE_BUS_OFF;
        }
 
        /* state hasn't changed */
@@ -1158,12 +1157,19 @@ static int flexcan_probe(struct platform_device *pdev)
        const struct flexcan_devtype_data *devtype_data;
        struct net_device *dev;
        struct flexcan_priv *priv;
+       struct regulator *reg_xceiver;
        struct resource *mem;
        struct clk *clk_ipg = NULL, *clk_per = NULL;
        void __iomem *base;
        int err, irq;
        u32 clock_freq = 0;
 
+       reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
+       if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       else if (IS_ERR(reg_xceiver))
+               reg_xceiver = NULL;
+
        if (pdev->dev.of_node)
                of_property_read_u32(pdev->dev.of_node,
                                                "clock-frequency", &clock_freq);
@@ -1224,9 +1230,7 @@ static int flexcan_probe(struct platform_device *pdev)
        priv->pdata = dev_get_platdata(&pdev->dev);
        priv->devtype_data = devtype_data;
 
-       priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
-       if (IS_ERR(priv->reg_xceiver))
-               priv->reg_xceiver = NULL;
+       priv->reg_xceiver = reg_xceiver;
 
        netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
 
index 009acc8..8b4d3e6 100644 (file)
@@ -901,6 +901,8 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
        }
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
        init_usb_anchor(&dev->rx_submitted);
 
        atomic_set(&dev->active_channels, 0);
index 2928f70..57611fd 100644 (file)
@@ -14,6 +14,8 @@
  * Copyright (C) 2015 Valeo S.A.
  */
 
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
 #include <linux/completion.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -23,7 +25,6 @@
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
-#define MAX_TX_URBS                    16
 #define MAX_RX_URBS                    4
 #define START_TIMEOUT                  1000 /* msecs */
 #define STOP_TIMEOUT                   1000 /* msecs */
@@ -441,6 +442,7 @@ struct kvaser_usb_error_summary {
        };
 };
 
+/* Context for an outstanding, not yet ACKed, transmission */
 struct kvaser_usb_tx_urb_context {
        struct kvaser_usb_net_priv *priv;
        u32 echo_index;
@@ -454,8 +456,13 @@ struct kvaser_usb {
        struct usb_endpoint_descriptor *bulk_in, *bulk_out;
        struct usb_anchor rx_submitted;
 
+       /* @max_tx_urbs: Firmware-reported maximum number of oustanding,
+        * not yet ACKed, transmissions on this device. This value is
+        * also used as a sentinel for marking free tx contexts.
+        */
        u32 fw_version;
        unsigned int nchannels;
+       unsigned int max_tx_urbs;
        enum kvaser_usb_family family;
 
        bool rxinitdone;
@@ -465,18 +472,18 @@ struct kvaser_usb {
 
 struct kvaser_usb_net_priv {
        struct can_priv can;
-
-       atomic_t active_tx_urbs;
-       struct usb_anchor tx_submitted;
-       struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
-
-       struct completion start_comp, stop_comp;
+       struct can_berr_counter bec;
 
        struct kvaser_usb *dev;
        struct net_device *netdev;
        int channel;
 
-       struct can_berr_counter bec;
+       struct completion start_comp, stop_comp;
+       struct usb_anchor tx_submitted;
+
+       spinlock_t tx_contexts_lock;
+       int active_tx_contexts;
+       struct kvaser_usb_tx_urb_context tx_contexts[];
 };
 
 static const struct usb_device_id kvaser_usb_table[] = {
@@ -584,8 +591,15 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
                while (pos <= actual_len - MSG_HEADER_LEN) {
                        tmp = buf + pos;
 
-                       if (!tmp->len)
-                               break;
+                       /* Handle messages crossing the USB endpoint max packet
+                        * size boundary. Check kvaser_usb_read_bulk_callback()
+                        * for further details.
+                        */
+                       if (tmp->len == 0) {
+                               pos = round_up(pos, le16_to_cpu(dev->bulk_in->
+                                                               wMaxPacketSize));
+                               continue;
+                       }
 
                        if (pos + tmp->len > actual_len) {
                                dev_err(dev->udev->dev.parent,
@@ -647,9 +661,13 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
        switch (dev->family) {
        case KVASER_LEAF:
                dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
+               dev->max_tx_urbs =
+                       le16_to_cpu(msg.u.leaf.softinfo.max_outstanding_tx);
                break;
        case KVASER_USBCAN:
                dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
+               dev->max_tx_urbs =
+                       le16_to_cpu(msg.u.usbcan.softinfo.max_outstanding_tx);
                break;
        }
 
@@ -686,6 +704,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
        struct kvaser_usb_net_priv *priv;
        struct sk_buff *skb;
        struct can_frame *cf;
+       unsigned long flags;
        u8 channel, tid;
 
        channel = msg->u.tx_acknowledge_header.channel;
@@ -704,7 +723,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 
        stats = &priv->netdev->stats;
 
-       context = &priv->tx_contexts[tid % MAX_TX_URBS];
+       context = &priv->tx_contexts[tid % dev->max_tx_urbs];
 
        /* Sometimes the state change doesn't come after a bus-off event */
        if (priv->can.restart_ms &&
@@ -729,12 +748,15 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 
        stats->tx_packets++;
        stats->tx_bytes += context->dlc;
-       can_get_echo_skb(priv->netdev, context->echo_index);
 
-       context->echo_index = MAX_TX_URBS;
-       atomic_dec(&priv->active_tx_urbs);
+       spin_lock_irqsave(&priv->tx_contexts_lock, flags);
 
+       can_get_echo_skb(priv->netdev, context->echo_index);
+       context->echo_index = dev->max_tx_urbs;
+       --priv->active_tx_contexts;
        netif_wake_queue(priv->netdev);
+
+       spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 }
 
 static void kvaser_usb_simple_msg_callback(struct urb *urb)
@@ -787,7 +809,6 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
                netdev_err(netdev, "Error transmitting URB\n");
                usb_unanchor_urb(urb);
                usb_free_urb(urb);
-               kfree(buf);
                return err;
        }
 
@@ -796,17 +817,6 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
        return 0;
 }
 
-static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
-{
-       int i;
-
-       usb_kill_anchored_urbs(&priv->tx_submitted);
-       atomic_set(&priv->active_tx_urbs, 0);
-
-       for (i = 0; i < MAX_TX_URBS; i++)
-               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
-}
-
 static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
                                                 const struct kvaser_usb_error_summary *es,
                                                 struct can_frame *cf)
@@ -1317,8 +1327,20 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
        while (pos <= urb->actual_length - MSG_HEADER_LEN) {
                msg = urb->transfer_buffer + pos;
 
-               if (!msg->len)
-                       break;
+               /* The Kvaser firmware can only read and write messages that
+                * does not cross the USB's endpoint wMaxPacketSize boundary.
+                * If a follow-up command crosses such boundary, firmware puts
+                * a placeholder zero-length command in its place then aligns
+                * the real command to the next max packet size.
+                *
+                * Handle such cases or we're going to miss a significant
+                * number of events in case of a heavy rx load on the bus.
+                */
+               if (msg->len == 0) {
+                       pos = round_up(pos, le16_to_cpu(dev->bulk_in->
+                                                       wMaxPacketSize));
+                       continue;
+               }
 
                if (pos + msg->len > urb->actual_length) {
                        dev_err(dev->udev->dev.parent, "Format error\n");
@@ -1326,7 +1348,6 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
                }
 
                kvaser_usb_handle_message(dev, msg);
-
                pos += msg->len;
        }
 
@@ -1498,6 +1519,26 @@ error:
        return err;
 }
 
+static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv)
+{
+       int i, max_tx_urbs;
+
+       max_tx_urbs = priv->dev->max_tx_urbs;
+
+       priv->active_tx_contexts = 0;
+       for (i = 0; i < max_tx_urbs; i++)
+               priv->tx_contexts[i].echo_index = max_tx_urbs;
+}
+
+/* This method might sleep. Do not call it in the atomic context
+ * of URB completions.
+ */
+static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
+{
+       usb_kill_anchored_urbs(&priv->tx_submitted);
+       kvaser_usb_reset_tx_urb_contexts(priv);
+}
+
 static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
 {
        int i;
@@ -1615,9 +1656,9 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        struct urb *urb;
        void *buf;
        struct kvaser_msg *msg;
-       int i, err;
-       int ret = NETDEV_TX_OK;
+       int i, err, ret = NETDEV_TX_OK;
        u8 *msg_tx_can_flags = NULL;            /* GCC */
+       unsigned long flags;
 
        if (can_dropped_invalid_skb(netdev, skb))
                return NETDEV_TX_OK;
@@ -1634,7 +1675,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        if (!buf) {
                stats->tx_dropped++;
                dev_kfree_skb(skb);
-               goto nobufmem;
+               goto freeurb;
        }
 
        msg = buf;
@@ -1671,22 +1712,32 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        if (cf->can_id & CAN_RTR_FLAG)
                *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
 
-       for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
-               if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+       spin_lock_irqsave(&priv->tx_contexts_lock, flags);
+       for (i = 0; i < dev->max_tx_urbs; i++) {
+               if (priv->tx_contexts[i].echo_index == dev->max_tx_urbs) {
                        context = &priv->tx_contexts[i];
+
+                       context->echo_index = i;
+                       can_put_echo_skb(skb, netdev, context->echo_index);
+                       ++priv->active_tx_contexts;
+                       if (priv->active_tx_contexts >= dev->max_tx_urbs)
+                               netif_stop_queue(netdev);
+
                        break;
                }
        }
+       spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 
        /* This should never happen; it implies a flow control bug */
        if (!context) {
                netdev_warn(netdev, "cannot find free context\n");
+
+               kfree(buf);
                ret =  NETDEV_TX_BUSY;
-               goto releasebuf;
+               goto freeurb;
        }
 
        context->priv = priv;
-       context->echo_index = i;
        context->dlc = cf->can_dlc;
 
        msg->u.tx_can.tid = context->echo_index;
@@ -1698,18 +1749,17 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                          kvaser_usb_write_bulk_callback, context);
        usb_anchor_urb(urb, &priv->tx_submitted);
 
-       can_put_echo_skb(skb, netdev, context->echo_index);
-
-       atomic_inc(&priv->active_tx_urbs);
-
-       if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
-               netif_stop_queue(netdev);
-
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (unlikely(err)) {
+               spin_lock_irqsave(&priv->tx_contexts_lock, flags);
+
                can_free_echo_skb(netdev, context->echo_index);
+               context->echo_index = dev->max_tx_urbs;
+               --priv->active_tx_contexts;
+               netif_wake_queue(netdev);
+
+               spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
 
-               atomic_dec(&priv->active_tx_urbs);
                usb_unanchor_urb(urb);
 
                stats->tx_dropped++;
@@ -1719,16 +1769,12 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                else
                        netdev_warn(netdev, "Failed tx_urb %d\n", err);
 
-               goto releasebuf;
+               goto freeurb;
        }
 
-       usb_free_urb(urb);
-
-       return NETDEV_TX_OK;
+       ret = NETDEV_TX_OK;
 
-releasebuf:
-       kfree(buf);
-nobufmem:
+freeurb:
        usb_free_urb(urb);
        return ret;
 }
@@ -1840,13 +1886,15 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
        struct kvaser_usb *dev = usb_get_intfdata(intf);
        struct net_device *netdev;
        struct kvaser_usb_net_priv *priv;
-       int i, err;
+       int err;
 
        err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel);
        if (err)
                return err;
 
-       netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+       netdev = alloc_candev(sizeof(*priv) +
+                             dev->max_tx_urbs * sizeof(*priv->tx_contexts),
+                             dev->max_tx_urbs);
        if (!netdev) {
                dev_err(&intf->dev, "Cannot alloc candev\n");
                return -ENOMEM;
@@ -1854,19 +1902,17 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
 
        priv = netdev_priv(netdev);
 
+       init_usb_anchor(&priv->tx_submitted);
        init_completion(&priv->start_comp);
        init_completion(&priv->stop_comp);
 
-       init_usb_anchor(&priv->tx_submitted);
-       atomic_set(&priv->active_tx_urbs, 0);
-
-       for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
-               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
-
        priv->dev = dev;
        priv->netdev = netdev;
        priv->channel = channel;
 
+       spin_lock_init(&priv->tx_contexts_lock);
+       kvaser_usb_reset_tx_urb_contexts(priv);
+
        priv->can.state = CAN_STATE_STOPPED;
        priv->can.clock.freq = CAN_USB_CLOCK;
        priv->can.bittiming_const = &kvaser_usb_bittiming_const;
@@ -1976,6 +2022,13 @@ static int kvaser_usb_probe(struct usb_interface *intf,
                return err;
        }
 
+       dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
+               ((dev->fw_version >> 24) & 0xff),
+               ((dev->fw_version >> 16) & 0xff),
+               (dev->fw_version & 0xffff));
+
+       dev_dbg(&intf->dev, "Max oustanding tx = %d URBs\n", dev->max_tx_urbs);
+
        err = kvaser_usb_get_card_info(dev);
        if (err) {
                dev_err(&intf->dev,
@@ -1983,11 +2036,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,
                return err;
        }
 
-       dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
-               ((dev->fw_version >> 24) & 0xff),
-               ((dev->fw_version >> 16) & 0xff),
-               (dev->fw_version & 0xffff));
-
        for (i = 0; i < dev->nchannels; i++) {
                err = kvaser_usb_init_one(intf, id, i);
                if (err) {
index 1ba7c25..e8fc495 100644 (file)
@@ -26,8 +26,8 @@
 #define PUCAN_CMD_FILTER_STD           0x008
 #define PUCAN_CMD_TX_ABORT             0x009
 #define PUCAN_CMD_WR_ERR_CNT           0x00a
-#define PUCAN_CMD_RX_FRAME_ENABLE      0x00b
-#define PUCAN_CMD_RX_FRAME_DISABLE     0x00c
+#define PUCAN_CMD_SET_EN_OPTION                0x00b
+#define PUCAN_CMD_CLR_DIS_OPTION       0x00c
 #define PUCAN_CMD_END_OF_COLLECTION    0x3ff
 
 /* uCAN received messages list */
@@ -101,14 +101,15 @@ struct __packed pucan_wr_err_cnt {
        u16     unused;
 };
 
-/* uCAN RX_FRAME_ENABLE command fields */
-#define PUCAN_FLTEXT_ERROR             0x0001
-#define PUCAN_FLTEXT_BUSLOAD           0x0002
+/* uCAN SET_EN/CLR_DIS _OPTION command fields */
+#define PUCAN_OPTION_ERROR             0x0001
+#define PUCAN_OPTION_BUSLOAD           0x0002
+#define PUCAN_OPTION_CANDFDISO         0x0004
 
-struct __packed pucan_filter_ext {
+struct __packed pucan_options {
        __le16  opcode_channel;
 
-       __le16  ext_mask;
+       __le16  options;
        u32     unused;
 };
 
index 962c3f0..a9221ad 100644 (file)
@@ -110,13 +110,13 @@ struct __packed pcan_ufd_led {
        u8      unused[5];
 };
 
-/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */
+/* Extended usage of uCAN commands CMD_xxx_xx_OPTION for PCAN-USB Pro FD */
 #define PCAN_UFD_FLTEXT_CALIBRATION    0x8000
 
-struct __packed pcan_ufd_filter_ext {
+struct __packed pcan_ufd_options {
        __le16  opcode_channel;
 
-       __le16  ext_mask;
+       __le16  ucan_mask;
        u16     unused;
        __le16  usb_mask;
 };
@@ -251,6 +251,27 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
        /* moves the pointer forward */
        pc += sizeof(struct pucan_wr_err_cnt);
 
+       /* add command to switch from ISO to non-ISO mode, if fw allows it */
+       if (dev->can.ctrlmode_supported & CAN_CTRLMODE_FD_NON_ISO) {
+               struct pucan_options *puo = (struct pucan_options *)pc;
+
+               puo->opcode_channel =
+                       (dev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) ?
+                       pucan_cmd_opcode_channel(dev,
+                                                PUCAN_CMD_CLR_DIS_OPTION) :
+                       pucan_cmd_opcode_channel(dev, PUCAN_CMD_SET_EN_OPTION);
+
+               puo->options = cpu_to_le16(PUCAN_OPTION_CANDFDISO);
+
+               /* to be sure that no other extended bits will be taken into
+                * account
+                */
+               puo->unused = 0;
+
+               /* moves the pointer forward */
+               pc += sizeof(struct pucan_options);
+       }
+
        /* next, go back to operational mode */
        cmd = (struct pucan_command *)pc;
        cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
@@ -321,21 +342,21 @@ static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx,
        return pcan_usb_fd_send_cmd(dev, cmd);
 }
 
-/* set/unset notifications filter:
+/* set/unset options
  *
- *     onoff   sets(1)/unset(0) notifications
- *     mask    each bit defines a kind of notification to set/unset
+ *     onoff   set(1)/unset(0) options
+ *     mask    each bit defines a kind of options to set/unset
  */
-static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev,
-                                     bool onoff, u16 ext_mask, u16 usb_mask)
+static int pcan_usb_fd_set_options(struct peak_usb_device *dev,
+                                  bool onoff, u16 ucan_mask, u16 usb_mask)
 {
-       struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev);
+       struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev);
 
        cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
-                                       (onoff) ? PUCAN_CMD_RX_FRAME_ENABLE :
-                                                 PUCAN_CMD_RX_FRAME_DISABLE);
+                                       (onoff) ? PUCAN_CMD_SET_EN_OPTION :
+                                                 PUCAN_CMD_CLR_DIS_OPTION);
 
-       cmd->ext_mask = cpu_to_le16(ext_mask);
+       cmd->ucan_mask = cpu_to_le16(ucan_mask);
        cmd->usb_mask = cpu_to_le16(usb_mask);
 
        /* send the command */
@@ -770,9 +791,9 @@ static int pcan_usb_fd_start(struct peak_usb_device *dev)
                                       &pcan_usb_pro_fd);
 
                /* enable USB calibration messages */
-               err = pcan_usb_fd_set_filter_ext(dev, 1,
-                                                PUCAN_FLTEXT_ERROR,
-                                                PCAN_UFD_FLTEXT_CALIBRATION);
+               err = pcan_usb_fd_set_options(dev, 1,
+                                             PUCAN_OPTION_ERROR,
+                                             PCAN_UFD_FLTEXT_CALIBRATION);
        }
 
        pdev->usb_if->dev_opened_count++;
@@ -806,9 +827,9 @@ static int pcan_usb_fd_stop(struct peak_usb_device *dev)
 
        /* turn off special msgs for that interface if no other dev opened */
        if (pdev->usb_if->dev_opened_count == 1)
-               pcan_usb_fd_set_filter_ext(dev, 0,
-                                          PUCAN_FLTEXT_ERROR,
-                                          PCAN_UFD_FLTEXT_CALIBRATION);
+               pcan_usb_fd_set_options(dev, 0,
+                                       PUCAN_OPTION_ERROR,
+                                       PCAN_UFD_FLTEXT_CALIBRATION);
        pdev->usb_if->dev_opened_count--;
 
        return 0;
@@ -860,8 +881,14 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
                         pdev->usb_if->fw_info.fw_version[2],
                         dev->adapter->ctrl_count);
 
-               /* the currently supported hw is non-ISO */
-               dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO;
+               /* check for ability to switch between ISO/non-ISO modes */
+               if (pdev->usb_if->fw_info.fw_version[0] >= 2) {
+                       /* firmware >= 2.x supports ISO/non-ISO switching */
+                       dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO;
+               } else {
+                       /* firmware < 2.x only supports fixed(!) non-ISO */
+                       dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO;
+               }
 
                /* tell the hardware the can driver is running */
                err = pcan_usb_fd_drv_loaded(dev, 1);
@@ -879,6 +906,10 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
 
                pdev->usb_if = ppdev->usb_if;
                pdev->cmd_buffer_addr = ppdev->cmd_buffer_addr;
+
+               /* do a copy of the ctrlmode[_supported] too */
+               dev->can.ctrlmode = ppdev->dev.can.ctrlmode;
+               dev->can.ctrlmode_supported = ppdev->dev.can.ctrlmode_supported;
        }
 
        pdev->usb_if->dev[dev->ctrl_idx] = dev;
@@ -933,9 +964,9 @@ static void pcan_usb_fd_exit(struct peak_usb_device *dev)
        if (dev->ctrl_idx == 0) {
                /* turn off calibration message if any device were opened */
                if (pdev->usb_if->dev_opened_count > 0)
-                       pcan_usb_fd_set_filter_ext(dev, 0,
-                                                  PUCAN_FLTEXT_ERROR,
-                                                  PCAN_UFD_FLTEXT_CALIBRATION);
+                       pcan_usb_fd_set_options(dev, 0,
+                                               PUCAN_OPTION_ERROR,
+                                               PCAN_UFD_FLTEXT_CALIBRATION);
 
                /* tell USB adapter that the driver is being unloaded */
                pcan_usb_fd_drv_loaded(dev, 0);
index ee9f650..7b7053d 100644 (file)
@@ -105,8 +105,8 @@ static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off)  \
 {                                                                      \
        u32 indir, dir;                                                 \
        spin_lock(&priv->indir_lock);                                   \
-       indir = reg_readl(priv, REG_DIR_DATA_READ);                     \
        dir = __raw_readl(priv->name + off);                            \
+       indir = reg_readl(priv, REG_DIR_DATA_READ);                     \
        spin_unlock(&priv->indir_lock);                                 \
        return (u64)indir << 32 | dir;                                  \
 }                                                                      \
index 7769c05..ec6eac1 100644 (file)
@@ -484,11 +484,8 @@ static int axnet_open(struct net_device *dev)
     link->open++;
 
     info->link_status = 0x00;
-    init_timer(&info->watchdog);
-    info->watchdog.function = ei_watchdog;
-    info->watchdog.data = (u_long)dev;
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
+    setup_timer(&info->watchdog, ei_watchdog, (u_long)dev);
+    mod_timer(&info->watchdog, jiffies + HZ);
 
     return ax_open(dev);
 } /* axnet_open */
index 9fb7b9d..2777289 100644 (file)
@@ -918,11 +918,8 @@ static int pcnet_open(struct net_device *dev)
 
     info->phy_id = info->eth_phy;
     info->link_status = 0x00;
-    init_timer(&info->watchdog);
-    info->watchdog.function = ei_watchdog;
-    info->watchdog.data = (u_long)dev;
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
+    setup_timer(&info->watchdog, ei_watchdog, (u_long)dev);
+    mod_timer(&info->watchdog, jiffies + HZ);
 
     return ei_open(dev);
 } /* pcnet_open */
index 760c72c..6725dc0 100644 (file)
@@ -376,7 +376,8 @@ static int tse_rx(struct altera_tse_private *priv, int limit)
        u16 pktlength;
        u16 pktstatus;
 
-       while ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) {
+       while (((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) &&
+              (count < limit))  {
                pktstatus = rxstatus >> 16;
                pktlength = rxstatus & 0xffff;
 
@@ -491,28 +492,27 @@ static int tse_poll(struct napi_struct *napi, int budget)
        struct altera_tse_private *priv =
                        container_of(napi, struct altera_tse_private, napi);
        int rxcomplete = 0;
-       int txcomplete = 0;
        unsigned long int flags;
 
-       txcomplete = tse_tx_complete(priv);
+       tse_tx_complete(priv);
 
        rxcomplete = tse_rx(priv, budget);
 
-       if (rxcomplete >= budget || txcomplete > 0)
-               return rxcomplete;
+       if (rxcomplete < budget) {
 
-       napi_gro_flush(napi, false);
-       __napi_complete(napi);
+               napi_gro_flush(napi, false);
+               __napi_complete(napi);
 
-       netdev_dbg(priv->dev,
-                  "NAPI Complete, did %d packets with budget %d\n",
-                  txcomplete+rxcomplete, budget);
+               netdev_dbg(priv->dev,
+                          "NAPI Complete, did %d packets with budget %d\n",
+                          rxcomplete, budget);
 
-       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
-       priv->dmaops->enable_rxirq(priv);
-       priv->dmaops->enable_txirq(priv);
-       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
-       return rxcomplete + txcomplete;
+               spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+               priv->dmaops->enable_rxirq(priv);
+               priv->dmaops->enable_txirq(priv);
+               spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+       }
+       return rxcomplete;
 }
 
 /* DMA TX & RX FIFO interrupt routing
@@ -521,7 +521,6 @@ static irqreturn_t altera_isr(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct altera_tse_private *priv;
-       unsigned long int flags;
 
        if (unlikely(!dev)) {
                pr_err("%s: invalid dev pointer\n", __func__);
@@ -529,20 +528,20 @@ static irqreturn_t altera_isr(int irq, void *dev_id)
        }
        priv = netdev_priv(dev);
 
-       /* turn off desc irqs and enable napi rx */
-       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       spin_lock(&priv->rxdma_irq_lock);
+       /* reset IRQs */
+       priv->dmaops->clear_rxirq(priv);
+       priv->dmaops->clear_txirq(priv);
+       spin_unlock(&priv->rxdma_irq_lock);
 
        if (likely(napi_schedule_prep(&priv->napi))) {
+               spin_lock(&priv->rxdma_irq_lock);
                priv->dmaops->disable_rxirq(priv);
                priv->dmaops->disable_txirq(priv);
+               spin_unlock(&priv->rxdma_irq_lock);
                __napi_schedule(&priv->napi);
        }
 
-       /* reset IRQs */
-       priv->dmaops->clear_rxirq(priv);
-       priv->dmaops->clear_txirq(priv);
-
-       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
 
        return IRQ_HANDLED;
 }
@@ -1399,7 +1398,7 @@ static int altera_tse_probe(struct platform_device *pdev)
        }
 
        if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
-                                &priv->rx_fifo_depth)) {
+                                &priv->tx_fifo_depth)) {
                dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n");
                ret = -ENXIO;
                goto err_free_netdev;
index 11d6e65..15a8190 100644 (file)
@@ -1543,7 +1543,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 {
        struct pcnet32_private *lp;
        int i, media;
-       int fdx, mii, fset, dxsuflo;
+       int fdx, mii, fset, dxsuflo, sram;
        int chip_version;
        char *chipname;
        struct net_device *dev;
@@ -1580,7 +1580,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
        }
 
        /* initialize variables */
-       fdx = mii = fset = dxsuflo = 0;
+       fdx = mii = fset = dxsuflo = sram = 0;
        chip_version = (chip_version >> 12) & 0xffff;
 
        switch (chip_version) {
@@ -1613,6 +1613,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                chipname = "PCnet/FAST III 79C973";     /* PCI */
                fdx = 1;
                mii = 1;
+               sram = 1;
                break;
        case 0x2626:
                chipname = "PCnet/Home 79C978"; /* PCI */
@@ -1636,6 +1637,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                chipname = "PCnet/FAST III 79C975";     /* PCI */
                fdx = 1;
                mii = 1;
+               sram = 1;
                break;
        case 0x2628:
                chipname = "PCnet/PRO 79C976";
@@ -1664,6 +1666,31 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                dxsuflo = 1;
        }
 
+       /*
+        * The Am79C973/Am79C975 controllers come with 12K of SRAM
+        * which we can use for the Tx/Rx buffers but most importantly,
+        * the use of SRAM allow us to use the BCR18:NOUFLO bit to avoid
+        * Tx fifo underflows.
+        */
+       if (sram) {
+               /*
+                * The SRAM is being configured in two steps. First we
+                * set the SRAM size in the BCR25:SRAM_SIZE bits. According
+                * to the datasheet, each bit corresponds to a 512-byte
+                * page so we can have at most 24 pages. The SRAM_SIZE
+                * holds the value of the upper 8 bits of the 16-bit SRAM size.
+                * The low 8-bits start at 0x00 and end at 0xff. So the
+                * address range is from 0x0000 up to 0x17ff. Therefore,
+                * the SRAM_SIZE is set to 0x17. The next step is to set
+                * the BCR26:SRAM_BND midway through so the Tx and Rx
+                * buffers can share the SRAM equally.
+                */
+               a->write_bcr(ioaddr, 25, 0x17);
+               a->write_bcr(ioaddr, 26, 0xc);
+               /* And finally enable the NOUFLO bit */
+               a->write_bcr(ioaddr, 18, a->read_bcr(ioaddr, 18) | (1 << 11));
+       }
+
        dev = alloc_etherdev(sizeof(*lp));
        if (!dev) {
                ret = -ENOMEM;
index b93d440..885b02b 100644 (file)
@@ -609,6 +609,68 @@ static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del)
        }
 }
 
+static int xgbe_request_irqs(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_channel *channel;
+       struct net_device *netdev = pdata->netdev;
+       unsigned int i;
+       int ret;
+
+       ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
+                              netdev->name, pdata);
+       if (ret) {
+               netdev_alert(netdev, "error requesting irq %d\n",
+                            pdata->dev_irq);
+               return ret;
+       }
+
+       if (!pdata->per_channel_irq)
+               return 0;
+
+       channel = pdata->channel;
+       for (i = 0; i < pdata->channel_count; i++, channel++) {
+               snprintf(channel->dma_irq_name,
+                        sizeof(channel->dma_irq_name) - 1,
+                        "%s-TxRx-%u", netdev_name(netdev),
+                        channel->queue_index);
+
+               ret = devm_request_irq(pdata->dev, channel->dma_irq,
+                                      xgbe_dma_isr, 0,
+                                      channel->dma_irq_name, channel);
+               if (ret) {
+                       netdev_alert(netdev, "error requesting irq %d\n",
+                                    channel->dma_irq);
+                       goto err_irq;
+               }
+       }
+
+       return 0;
+
+err_irq:
+       /* Using an unsigned int, 'i' will go to UINT_MAX and exit */
+       for (i--, channel--; i < pdata->channel_count; i--, channel--)
+               devm_free_irq(pdata->dev, channel->dma_irq, channel);
+
+       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
+
+       return ret;
+}
+
+static void xgbe_free_irqs(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_channel *channel;
+       unsigned int i;
+
+       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
+
+       if (!pdata->per_channel_irq)
+               return;
+
+       channel = pdata->channel;
+       for (i = 0; i < pdata->channel_count; i++, channel++)
+               devm_free_irq(pdata->dev, channel->dma_irq, channel);
+}
+
 void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata)
 {
        struct xgbe_hw_if *hw_if = &pdata->hw_if;
@@ -810,20 +872,20 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
                return -EINVAL;
        }
 
-       phy_stop(pdata->phydev);
-
        spin_lock_irqsave(&pdata->lock, flags);
 
        if (caller == XGMAC_DRIVER_CONTEXT)
                netif_device_detach(netdev);
 
        netif_tx_stop_all_queues(netdev);
-       xgbe_napi_disable(pdata, 0);
 
-       /* Powerdown Tx/Rx */
        hw_if->powerdown_tx(pdata);
        hw_if->powerdown_rx(pdata);
 
+       xgbe_napi_disable(pdata, 0);
+
+       phy_stop(pdata->phydev);
+
        pdata->power_down = 1;
 
        spin_unlock_irqrestore(&pdata->lock, flags);
@@ -854,14 +916,14 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
 
        phy_start(pdata->phydev);
 
-       /* Enable Tx/Rx */
+       xgbe_napi_enable(pdata, 0);
+
        hw_if->powerup_tx(pdata);
        hw_if->powerup_rx(pdata);
 
        if (caller == XGMAC_DRIVER_CONTEXT)
                netif_device_attach(netdev);
 
-       xgbe_napi_enable(pdata, 0);
        netif_tx_start_all_queues(netdev);
 
        spin_unlock_irqrestore(&pdata->lock, flags);
@@ -875,6 +937,7 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
 {
        struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct net_device *netdev = pdata->netdev;
+       int ret;
 
        DBGPR("-->xgbe_start\n");
 
@@ -884,17 +947,31 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
 
        phy_start(pdata->phydev);
 
+       xgbe_napi_enable(pdata, 1);
+
+       ret = xgbe_request_irqs(pdata);
+       if (ret)
+               goto err_napi;
+
        hw_if->enable_tx(pdata);
        hw_if->enable_rx(pdata);
 
        xgbe_init_tx_timers(pdata);
 
-       xgbe_napi_enable(pdata, 1);
        netif_tx_start_all_queues(netdev);
 
        DBGPR("<--xgbe_start\n");
 
        return 0;
+
+err_napi:
+       xgbe_napi_disable(pdata, 1);
+
+       phy_stop(pdata->phydev);
+
+       hw_if->exit(pdata);
+
+       return ret;
 }
 
 static void xgbe_stop(struct xgbe_prv_data *pdata)
@@ -907,16 +984,21 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
 
        DBGPR("-->xgbe_stop\n");
 
-       phy_stop(pdata->phydev);
-
        netif_tx_stop_all_queues(netdev);
-       xgbe_napi_disable(pdata, 1);
 
        xgbe_stop_tx_timers(pdata);
 
        hw_if->disable_tx(pdata);
        hw_if->disable_rx(pdata);
 
+       xgbe_free_irqs(pdata);
+
+       xgbe_napi_disable(pdata, 1);
+
+       phy_stop(pdata->phydev);
+
+       hw_if->exit(pdata);
+
        channel = pdata->channel;
        for (i = 0; i < pdata->channel_count; i++, channel++) {
                if (!channel->tx_ring)
@@ -931,10 +1013,6 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
 
 static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
 {
-       struct xgbe_channel *channel;
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
-       unsigned int i;
-
        DBGPR("-->xgbe_restart_dev\n");
 
        /* If not running, "restart" will happen on open */
@@ -942,19 +1020,10 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
                return;
 
        xgbe_stop(pdata);
-       synchronize_irq(pdata->dev_irq);
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++)
-                       synchronize_irq(channel->dma_irq);
-       }
 
        xgbe_free_tx_data(pdata);
        xgbe_free_rx_data(pdata);
 
-       /* Issue software reset to device */
-       hw_if->exit(pdata);
-
        xgbe_start(pdata);
 
        DBGPR("<--xgbe_restart_dev\n");
@@ -1283,10 +1352,7 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata,
 static int xgbe_open(struct net_device *netdev)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct xgbe_desc_if *desc_if = &pdata->desc_if;
-       struct xgbe_channel *channel = NULL;
-       unsigned int i = 0;
        int ret;
 
        DBGPR("-->xgbe_open\n");
@@ -1329,55 +1395,14 @@ static int xgbe_open(struct net_device *netdev)
        INIT_WORK(&pdata->restart_work, xgbe_restart);
        INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp);
 
-       /* Request interrupts */
-       ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
-                              netdev->name, pdata);
-       if (ret) {
-               netdev_alert(netdev, "error requesting irq %d\n",
-                            pdata->dev_irq);
-               goto err_rings;
-       }
-
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++) {
-                       snprintf(channel->dma_irq_name,
-                                sizeof(channel->dma_irq_name) - 1,
-                                "%s-TxRx-%u", netdev_name(netdev),
-                                channel->queue_index);
-
-                       ret = devm_request_irq(pdata->dev, channel->dma_irq,
-                                              xgbe_dma_isr, 0,
-                                              channel->dma_irq_name, channel);
-                       if (ret) {
-                               netdev_alert(netdev,
-                                            "error requesting irq %d\n",
-                                            channel->dma_irq);
-                               goto err_irq;
-                       }
-               }
-       }
-
        ret = xgbe_start(pdata);
        if (ret)
-               goto err_start;
+               goto err_rings;
 
        DBGPR("<--xgbe_open\n");
 
        return 0;
 
-err_start:
-       hw_if->exit(pdata);
-
-err_irq:
-       if (pdata->per_channel_irq) {
-               /* Using an unsigned int, 'i' will go to UINT_MAX and exit */
-               for (i--, channel--; i < pdata->channel_count; i--, channel--)
-                       devm_free_irq(pdata->dev, channel->dma_irq, channel);
-       }
-
-       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
-
 err_rings:
        desc_if->free_ring_resources(pdata);
 
@@ -1399,30 +1424,16 @@ err_phy_init:
 static int xgbe_close(struct net_device *netdev)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct xgbe_desc_if *desc_if = &pdata->desc_if;
-       struct xgbe_channel *channel;
-       unsigned int i;
 
        DBGPR("-->xgbe_close\n");
 
        /* Stop the device */
        xgbe_stop(pdata);
 
-       /* Issue software reset to device */
-       hw_if->exit(pdata);
-
        /* Free the ring descriptors and buffers */
        desc_if->free_ring_resources(pdata);
 
-       /* Release the interrupts */
-       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++)
-                       devm_free_irq(pdata->dev, channel->dma_irq, channel);
-       }
-
        /* Free the channel and ring structures */
        xgbe_free_channels(pdata);
 
index 869d97f..b927021 100644 (file)
@@ -593,7 +593,7 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
        if (!xgene_ring_mgr_init(pdata))
                return -ENODEV;
 
-       if (!efi_enabled(EFI_BOOT)) {
+       if (pdata->clk) {
                clk_prepare_enable(pdata->clk);
                clk_disable_unprepare(pdata->clk);
                clk_prepare_enable(pdata->clk);
index 4de62b2..635a83b 100644 (file)
@@ -1025,6 +1025,8 @@ static int xgene_enet_remove(struct platform_device *pdev)
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xgene_enet_acpi_match[] = {
        { "APMC0D05", },
+       { "APMC0D30", },
+       { "APMC0D31", },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
@@ -1033,6 +1035,8 @@ MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
 #ifdef CONFIG_OF
 static struct of_device_id xgene_enet_of_match[] = {
        {.compatible = "apm,xgene-enet",},
+       {.compatible = "apm,xgene1-sgenet",},
+       {.compatible = "apm,xgene1-xgenet",},
        {},
 };
 
index 21206d3..a7f2cc3 100644 (file)
@@ -486,7 +486,7 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
 {
        struct bcm_enet_priv *priv;
        struct net_device *dev;
-       int tx_work_done, rx_work_done;
+       int rx_work_done;
 
        priv = container_of(napi, struct bcm_enet_priv, napi);
        dev = priv->net_dev;
@@ -498,14 +498,14 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
                         ENETDMAC_IR, priv->tx_chan);
 
        /* reclaim sent skb */
-       tx_work_done = bcm_enet_tx_reclaim(dev, 0);
+       bcm_enet_tx_reclaim(dev, 0);
 
        spin_lock(&priv->rx_lock);
        rx_work_done = bcm_enet_receive_queue(dev, budget);
        spin_unlock(&priv->rx_lock);
 
-       if (rx_work_done >= budget || tx_work_done > 0) {
-               /* rx/tx queue is not yet empty/clean */
+       if (rx_work_done >= budget) {
+               /* rx queue is not yet empty/clean */
                return rx_work_done;
        }
 
index 5b308a4..783543a 100644 (file)
@@ -274,9 +274,9 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
        /* RBUF misc statistics */
        STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR),
        STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR),
-       STAT_MIB_RX("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
-       STAT_MIB_RX("rx_dma_failed", mib.rx_dma_failed),
-       STAT_MIB_TX("tx_dma_failed", mib.tx_dma_failed),
+       STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
+       STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed),
+       STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed),
 };
 
 #define BCM_SYSPORT_STATS_LEN  ARRAY_SIZE(bcm_sysport_gstrings_stats)
@@ -345,6 +345,7 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv)
                s = &bcm_sysport_gstrings_stats[i];
                switch (s->type) {
                case BCM_SYSPORT_STAT_NETDEV:
+               case BCM_SYSPORT_STAT_SOFT:
                        continue;
                case BCM_SYSPORT_STAT_MIB_RX:
                case BCM_SYSPORT_STAT_MIB_TX:
index fc19417..7e3d87a 100644 (file)
@@ -570,6 +570,7 @@ enum bcm_sysport_stat_type {
        BCM_SYSPORT_STAT_RUNT,
        BCM_SYSPORT_STAT_RXCHK,
        BCM_SYSPORT_STAT_RBUF,
+       BCM_SYSPORT_STAT_SOFT,
 };
 
 /* Macros to help define ethtool statistics */
@@ -590,6 +591,7 @@ enum bcm_sysport_stat_type {
 #define STAT_MIB_RX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_RX)
 #define STAT_MIB_TX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_TX)
 #define STAT_RUNT(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_RUNT)
+#define STAT_MIB_SOFT(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_SOFT)
 
 #define STAT_RXCHK(str, m, ofs) { \
        .stat_string = str, \
index 676ffe0..0469f72 100644 (file)
@@ -302,9 +302,6 @@ static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
        slot->skb = skb;
        slot->dma_addr = dma_addr;
 
-       if (slot->dma_addr & 0xC0000000)
-               bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
-
        return 0;
 }
 
@@ -505,8 +502,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                                  ring->mmio_base);
                        goto err_dma_free;
                }
-               if (ring->dma_base & 0xC0000000)
-                       bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
 
                ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
                                                      BGMAC_DMA_RING_TX);
@@ -536,8 +531,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                        err = -ENOMEM;
                        goto err_dma_free;
                }
-               if (ring->dma_base & 0xC0000000)
-                       bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
 
                ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
                                                      BGMAC_DMA_RING_RX);
index 756053c..4085c4b 100644 (file)
@@ -1811,7 +1811,7 @@ struct bnx2x {
        int                     stats_state;
 
        /* used for synchronization of concurrent threads statistics handling */
-       spinlock_t              stats_lock;
+       struct mutex            stats_lock;
 
        /* used by dmae command loader */
        struct dmae_command     stats_dmae;
@@ -1935,8 +1935,6 @@ struct bnx2x {
 
        int fp_array_size;
        u32 dump_preset_idx;
-       bool                                    stats_started;
-       struct semaphore                        stats_sema;
 
        u8                                      phys_port_id[ETH_ALEN];
 
index 7155e1d..1ec635f 100644 (file)
@@ -129,8 +129,8 @@ struct bnx2x_mac_vals {
        u32 xmac_val;
        u32 emac_addr;
        u32 emac_val;
-       u32 umac_addr;
-       u32 umac_val;
+       u32 umac_addr[2];
+       u32 umac_val[2];
        u32 bmac_addr;
        u32 bmac_val[2];
 };
@@ -7866,6 +7866,20 @@ int bnx2x_init_hw_func_cnic(struct bnx2x *bp)
        return 0;
 }
 
+/* previous driver DMAE transaction may have occurred when pre-boot stage ended
+ * and boot began, or when kdump kernel was loaded. Either case would invalidate
+ * the addresses of the transaction, resulting in was-error bit set in the pci
+ * causing all hw-to-host pcie transactions to timeout. If this happened we want
+ * to clear the interrupt which detected this from the pglueb and the was done
+ * bit
+ */
+static void bnx2x_clean_pglue_errors(struct bnx2x *bp)
+{
+       if (!CHIP_IS_E1x(bp))
+               REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
+                      1 << BP_ABS_FUNC(bp));
+}
+
 static int bnx2x_init_hw_func(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
@@ -7958,8 +7972,7 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_PGLUE_B, init_phase);
 
-       if (!CHIP_IS_E1x(bp))
-               REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, func);
+       bnx2x_clean_pglue_errors(bp);
 
        bnx2x_init_block(bp, BLOCK_ATC, init_phase);
        bnx2x_init_block(bp, BLOCK_DMAE, init_phase);
@@ -10141,6 +10154,25 @@ static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
        return base + (BP_ABS_FUNC(bp)) * stride;
 }
 
+static bool bnx2x_prev_unload_close_umac(struct bnx2x *bp,
+                                        u8 port, u32 reset_reg,
+                                        struct bnx2x_mac_vals *vals)
+{
+       u32 mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
+       u32 base_addr;
+
+       if (!(mask & reset_reg))
+               return false;
+
+       BNX2X_DEV_INFO("Disable umac Rx %02x\n", port);
+       base_addr = port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
+       vals->umac_addr[port] = base_addr + UMAC_REG_COMMAND_CONFIG;
+       vals->umac_val[port] = REG_RD(bp, vals->umac_addr[port]);
+       REG_WR(bp, vals->umac_addr[port], 0);
+
+       return true;
+}
+
 static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
                                        struct bnx2x_mac_vals *vals)
 {
@@ -10149,10 +10181,7 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
        u8 port = BP_PORT(bp);
 
        /* reset addresses as they also mark which values were changed */
-       vals->bmac_addr = 0;
-       vals->umac_addr = 0;
-       vals->xmac_addr = 0;
-       vals->emac_addr = 0;
+       memset(vals, 0, sizeof(*vals));
 
        reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2);
 
@@ -10201,15 +10230,11 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
                        REG_WR(bp, vals->xmac_addr, 0);
                        mac_stopped = true;
                }
-               mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
-               if (mask & reset_reg) {
-                       BNX2X_DEV_INFO("Disable umac Rx\n");
-                       base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
-                       vals->umac_addr = base_addr + UMAC_REG_COMMAND_CONFIG;
-                       vals->umac_val = REG_RD(bp, vals->umac_addr);
-                       REG_WR(bp, vals->umac_addr, 0);
-                       mac_stopped = true;
-               }
+
+               mac_stopped |= bnx2x_prev_unload_close_umac(bp, 0,
+                                                           reset_reg, vals);
+               mac_stopped |= bnx2x_prev_unload_close_umac(bp, 1,
+                                                           reset_reg, vals);
        }
 
        if (mac_stopped)
@@ -10505,8 +10530,11 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                /* Close the MAC Rx to prevent BRB from filling up */
                bnx2x_prev_unload_close_mac(bp, &mac_vals);
 
-               /* close LLH filters towards the BRB */
+               /* close LLH filters for both ports towards the BRB */
+               bnx2x_set_rx_filter(&bp->link_params, 0);
+               bp->link_params.port ^= 1;
                bnx2x_set_rx_filter(&bp->link_params, 0);
+               bp->link_params.port ^= 1;
 
                /* Check if the UNDI driver was previously loaded */
                if (bnx2x_prev_is_after_undi(bp)) {
@@ -10553,8 +10581,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
 
        if (mac_vals.xmac_addr)
                REG_WR(bp, mac_vals.xmac_addr, mac_vals.xmac_val);
-       if (mac_vals.umac_addr)
-               REG_WR(bp, mac_vals.umac_addr, mac_vals.umac_val);
+       if (mac_vals.umac_addr[0])
+               REG_WR(bp, mac_vals.umac_addr[0], mac_vals.umac_val[0]);
+       if (mac_vals.umac_addr[1])
+               REG_WR(bp, mac_vals.umac_addr[1], mac_vals.umac_val[1]);
        if (mac_vals.emac_addr)
                REG_WR(bp, mac_vals.emac_addr, mac_vals.emac_val);
        if (mac_vals.bmac_addr) {
@@ -10571,26 +10601,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
        return bnx2x_prev_mcp_done(bp);
 }
 
-/* previous driver DMAE transaction may have occurred when pre-boot stage ended
- * and boot began, or when kdump kernel was loaded. Either case would invalidate
- * the addresses of the transaction, resulting in was-error bit set in the pci
- * causing all hw-to-host pcie transactions to timeout. If this happened we want
- * to clear the interrupt which detected this from the pglueb and the was done
- * bit
- */
-static void bnx2x_prev_interrupted_dmae(struct bnx2x *bp)
-{
-       if (!CHIP_IS_E1x(bp)) {
-               u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS);
-               if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) {
-                       DP(BNX2X_MSG_SP,
-                          "'was error' bit was found to be set in pglueb upon startup. Clearing\n");
-                       REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
-                              1 << BP_FUNC(bp));
-               }
-       }
-}
-
 static int bnx2x_prev_unload(struct bnx2x *bp)
 {
        int time_counter = 10;
@@ -10600,7 +10610,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
        /* clear hw from errors which may have resulted from an interrupted
         * dmae transaction.
         */
-       bnx2x_prev_interrupted_dmae(bp);
+       bnx2x_clean_pglue_errors(bp);
 
        /* Release previously held locks */
        hw_lock_reg = (BP_FUNC(bp) <= 5) ?
@@ -12037,9 +12047,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        mutex_init(&bp->port.phy_mutex);
        mutex_init(&bp->fw_mb_mutex);
        mutex_init(&bp->drv_info_mutex);
+       mutex_init(&bp->stats_lock);
        bp->drv_info_mng_owner = false;
-       spin_lock_init(&bp->stats_lock);
-       sema_init(&bp->stats_sema, 1);
 
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
        INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
@@ -12722,6 +12731,9 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
        pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
                               PCICFG_VENDOR_ID_OFFSET);
 
+       /* Set PCIe reset type to fundamental for EEH recovery */
+       pdev->needs_freset = 1;
+
        /* AER (Advanced Error reporting) configuration */
        rc = pci_enable_pcie_error_reporting(pdev);
        if (!rc)
@@ -12766,7 +12778,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
                NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
                NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO |
                NETIF_F_RXHASH | NETIF_F_HW_VLAN_CTAG_TX;
-       if (!CHIP_IS_E1x(bp)) {
+       if (!chip_is_e1x) {
                dev->hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL |
                                    NETIF_F_GSO_IPIP | NETIF_F_GSO_SIT;
                dev->hw_enc_features =
@@ -13665,9 +13677,9 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
        cancel_delayed_work_sync(&bp->sp_task);
        cancel_delayed_work_sync(&bp->period_task);
 
-       spin_lock_bh(&bp->stats_lock);
+       mutex_lock(&bp->stats_lock);
        bp->stats_state = STATS_STATE_DISABLED;
-       spin_unlock_bh(&bp->stats_lock);
+       mutex_unlock(&bp->stats_lock);
 
        bnx2x_save_statistics(bp);
 
index e5aca2d..cfe3c76 100644 (file)
@@ -2238,7 +2238,9 @@ int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
 
                cookie.vf = vf;
                cookie.state = VF_ACQUIRED;
-               bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
+               rc = bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
+               if (rc)
+                       goto op_err;
        }
 
        DP(BNX2X_MSG_IOV, "set state to acquired\n");
index d160829..800ab44 100644 (file)
@@ -123,36 +123,28 @@ static void bnx2x_dp_stats(struct bnx2x *bp)
  */
 static void bnx2x_storm_stats_post(struct bnx2x *bp)
 {
-       if (!bp->stats_pending) {
-               int rc;
+       int rc;
 
-               spin_lock_bh(&bp->stats_lock);
-
-               if (bp->stats_pending) {
-                       spin_unlock_bh(&bp->stats_lock);
-                       return;
-               }
-
-               bp->fw_stats_req->hdr.drv_stats_counter =
-                       cpu_to_le16(bp->stats_counter++);
+       if (bp->stats_pending)
+               return;
 
-               DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
-                  le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter));
+       bp->fw_stats_req->hdr.drv_stats_counter =
+               cpu_to_le16(bp->stats_counter++);
 
-               /* adjust the ramrod to include VF queues statistics */
-               bnx2x_iov_adjust_stats_req(bp);
-               bnx2x_dp_stats(bp);
+       DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
+          le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter));
 
-               /* send FW stats ramrod */
-               rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
-                                  U64_HI(bp->fw_stats_req_mapping),
-                                  U64_LO(bp->fw_stats_req_mapping),
-                                  NONE_CONNECTION_TYPE);
-               if (rc == 0)
-                       bp->stats_pending = 1;
+       /* adjust the ramrod to include VF queues statistics */
+       bnx2x_iov_adjust_stats_req(bp);
+       bnx2x_dp_stats(bp);
 
-               spin_unlock_bh(&bp->stats_lock);
-       }
+       /* send FW stats ramrod */
+       rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
+                          U64_HI(bp->fw_stats_req_mapping),
+                          U64_LO(bp->fw_stats_req_mapping),
+                          NONE_CONNECTION_TYPE);
+       if (rc == 0)
+               bp->stats_pending = 1;
 }
 
 static void bnx2x_hw_stats_post(struct bnx2x *bp)
@@ -221,7 +213,7 @@ static void bnx2x_stats_comp(struct bnx2x *bp)
  */
 
 /* should be called under stats_sema */
-static void __bnx2x_stats_pmf_update(struct bnx2x *bp)
+static void bnx2x_stats_pmf_update(struct bnx2x *bp)
 {
        struct dmae_command *dmae;
        u32 opcode;
@@ -519,7 +511,7 @@ static void bnx2x_func_stats_init(struct bnx2x *bp)
 }
 
 /* should be called under stats_sema */
-static void __bnx2x_stats_start(struct bnx2x *bp)
+static void bnx2x_stats_start(struct bnx2x *bp)
 {
        if (IS_PF(bp)) {
                if (bp->port.pmf)
@@ -531,34 +523,13 @@ static void __bnx2x_stats_start(struct bnx2x *bp)
                bnx2x_hw_stats_post(bp);
                bnx2x_storm_stats_post(bp);
        }
-
-       bp->stats_started = true;
-}
-
-static void bnx2x_stats_start(struct bnx2x *bp)
-{
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_pmf_start(struct bnx2x *bp)
 {
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
        bnx2x_stats_comp(bp);
-       __bnx2x_stats_pmf_update(bp);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
-}
-
-static void bnx2x_stats_pmf_update(struct bnx2x *bp)
-{
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-       __bnx2x_stats_pmf_update(bp);
-       up(&bp->stats_sema);
+       bnx2x_stats_pmf_update(bp);
+       bnx2x_stats_start(bp);
 }
 
 static void bnx2x_stats_restart(struct bnx2x *bp)
@@ -568,11 +539,9 @@ static void bnx2x_stats_restart(struct bnx2x *bp)
         */
        if (IS_VF(bp))
                return;
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
+
        bnx2x_stats_comp(bp);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
+       bnx2x_stats_start(bp);
 }
 
 static void bnx2x_bmac_stats_update(struct bnx2x *bp)
@@ -1246,18 +1215,12 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 {
        u32 *stats_comp = bnx2x_sp(bp, stats_comp);
 
-       /* we run update from timer context, so give up
-        * if somebody is in the middle of transition
-        */
-       if (down_trylock(&bp->stats_sema))
+       if (bnx2x_edebug_stats_stopped(bp))
                return;
 
-       if (bnx2x_edebug_stats_stopped(bp) || !bp->stats_started)
-               goto out;
-
        if (IS_PF(bp)) {
                if (*stats_comp != DMAE_COMP_VAL)
-                       goto out;
+                       return;
 
                if (bp->port.pmf)
                        bnx2x_hw_stats_update(bp);
@@ -1267,7 +1230,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
                                BNX2X_ERR("storm stats were not updated for 3 times\n");
                                bnx2x_panic();
                        }
-                       goto out;
+                       return;
                }
        } else {
                /* vf doesn't collect HW statistics, and doesn't get completions
@@ -1281,7 +1244,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
        /* vf is done */
        if (IS_VF(bp))
-               goto out;
+               return;
 
        if (netif_msg_timer(bp)) {
                struct bnx2x_eth_stats *estats = &bp->eth_stats;
@@ -1292,9 +1255,6 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
        bnx2x_hw_stats_post(bp);
        bnx2x_storm_stats_post(bp);
-
-out:
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_port_stats_stop(struct bnx2x *bp)
@@ -1358,12 +1318,7 @@ static void bnx2x_port_stats_stop(struct bnx2x *bp)
 
 static void bnx2x_stats_stop(struct bnx2x *bp)
 {
-       int update = 0;
-
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-
-       bp->stats_started = false;
+       bool update = false;
 
        bnx2x_stats_comp(bp);
 
@@ -1381,8 +1336,6 @@ static void bnx2x_stats_stop(struct bnx2x *bp)
                bnx2x_hw_stats_post(bp);
                bnx2x_stats_comp(bp);
        }
-
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_do_nothing(struct bnx2x *bp)
@@ -1410,18 +1363,28 @@ static const struct {
 
 void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
 {
-       enum bnx2x_stats_state state;
-       void (*action)(struct bnx2x *bp);
+       enum bnx2x_stats_state state = bp->stats_state;
+
        if (unlikely(bp->panic))
                return;
 
-       spin_lock_bh(&bp->stats_lock);
-       state = bp->stats_state;
+       /* Statistics update run from timer context, and we don't want to stop
+        * that context in case someone is in the middle of a transition.
+        * For other events, wait a bit until lock is taken.
+        */
+       if (!mutex_trylock(&bp->stats_lock)) {
+               if (event == STATS_EVENT_UPDATE)
+                       return;
+
+               DP(BNX2X_MSG_STATS,
+                  "Unlikely stats' lock contention [event %d]\n", event);
+               mutex_lock(&bp->stats_lock);
+       }
+
+       bnx2x_stats_stm[state][event].action(bp);
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
-       action = bnx2x_stats_stm[state][event].action;
-       spin_unlock_bh(&bp->stats_lock);
 
-       action(bp);
+       mutex_unlock(&bp->stats_lock);
 
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
@@ -1998,13 +1961,34 @@ void bnx2x_afex_collect_stats(struct bnx2x *bp, void *void_afex_stats,
        }
 }
 
-void bnx2x_stats_safe_exec(struct bnx2x *bp,
-                          void (func_to_exec)(void *cookie),
-                          void *cookie){
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
+int bnx2x_stats_safe_exec(struct bnx2x *bp,
+                         void (func_to_exec)(void *cookie),
+                         void *cookie)
+{
+       int cnt = 10, rc = 0;
+
+       /* Wait for statistics to end [while blocking further requests],
+        * then run supplied function 'safely'.
+        */
+       mutex_lock(&bp->stats_lock);
+
        bnx2x_stats_comp(bp);
+       while (bp->stats_pending && cnt--)
+               if (bnx2x_storm_stats_update(bp))
+                       usleep_range(1000, 2000);
+       if (bp->stats_pending) {
+               BNX2X_ERR("Failed to wait for stats pending to clear [possibly FW is stuck]\n");
+               rc = -EBUSY;
+               goto out;
+       }
+
        func_to_exec(cookie);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
+
+out:
+       /* No need to restart statistics - if they're enabled, the timer
+        * will restart the statistics.
+        */
+       mutex_unlock(&bp->stats_lock);
+
+       return rc;
 }
index 2beceae..965539a 100644 (file)
@@ -539,9 +539,9 @@ struct bnx2x;
 void bnx2x_memset_stats(struct bnx2x *bp);
 void bnx2x_stats_init(struct bnx2x *bp);
 void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
-void bnx2x_stats_safe_exec(struct bnx2x *bp,
-                          void (func_to_exec)(void *cookie),
-                          void *cookie);
+int bnx2x_stats_safe_exec(struct bnx2x *bp,
+                         void (func_to_exec)(void *cookie),
+                         void *cookie);
 
 /**
  * bnx2x_save_statistics - save statistics when unloading.
index ff83c46..6befde6 100644 (file)
@@ -487,6 +487,7 @@ enum bcmgenet_stat_type {
        BCMGENET_STAT_MIB_TX,
        BCMGENET_STAT_RUNT,
        BCMGENET_STAT_MISC,
+       BCMGENET_STAT_SOFT,
 };
 
 struct bcmgenet_stats {
@@ -515,6 +516,7 @@ struct bcmgenet_stats {
 #define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX)
 #define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX)
 #define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT)
+#define STAT_GENET_SOFT_MIB(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_SOFT)
 
 #define STAT_GENET_MISC(str, m, offset) { \
        .stat_string = str, \
@@ -614,9 +616,9 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = {
                        UMAC_RBUF_OVFL_CNT),
        STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT),
        STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT),
-       STAT_GENET_MIB_RX("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
-       STAT_GENET_MIB_RX("rx_dma_failed", mib.rx_dma_failed),
-       STAT_GENET_MIB_TX("tx_dma_failed", mib.tx_dma_failed),
+       STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
+       STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed),
+       STAT_GENET_SOFT_MIB("tx_dma_failed", mib.tx_dma_failed),
 };
 
 #define BCMGENET_STATS_LEN     ARRAY_SIZE(bcmgenet_gstrings_stats)
@@ -668,6 +670,7 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
                s = &bcmgenet_gstrings_stats[i];
                switch (s->type) {
                case BCMGENET_STAT_NETDEV:
+               case BCMGENET_STAT_SOFT:
                        continue;
                case BCMGENET_STAT_MIB_RX:
                case BCMGENET_STAT_MIB_TX:
@@ -971,13 +974,14 @@ static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv,
 }
 
 /* Unlocked version of the reclaim routine */
-static void __bcmgenet_tx_reclaim(struct net_device *dev,
-                                 struct bcmgenet_tx_ring *ring)
+static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
+                                         struct bcmgenet_tx_ring *ring)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        int last_tx_cn, last_c_index, num_tx_bds;
        struct enet_cb *tx_cb_ptr;
        struct netdev_queue *txq;
+       unsigned int pkts_compl = 0;
        unsigned int bds_compl;
        unsigned int c_index;
 
@@ -1005,6 +1009,7 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
                tx_cb_ptr = ring->cbs + last_c_index;
                bds_compl = 0;
                if (tx_cb_ptr->skb) {
+                       pkts_compl++;
                        bds_compl = skb_shinfo(tx_cb_ptr->skb)->nr_frags + 1;
                        dev->stats.tx_bytes += tx_cb_ptr->skb->len;
                        dma_unmap_single(&dev->dev,
@@ -1028,23 +1033,45 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
                last_c_index &= (num_tx_bds - 1);
        }
 
-       if (ring->free_bds > (MAX_SKB_FRAGS + 1))
-               ring->int_disable(priv, ring);
-
-       if (netif_tx_queue_stopped(txq))
-               netif_tx_wake_queue(txq);
+       if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
+               if (netif_tx_queue_stopped(txq))
+                       netif_tx_wake_queue(txq);
+       }
 
        ring->c_index = c_index;
+
+       return pkts_compl;
 }
 
-static void bcmgenet_tx_reclaim(struct net_device *dev,
+static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
                                struct bcmgenet_tx_ring *ring)
 {
+       unsigned int released;
        unsigned long flags;
 
        spin_lock_irqsave(&ring->lock, flags);
-       __bcmgenet_tx_reclaim(dev, ring);
+       released = __bcmgenet_tx_reclaim(dev, ring);
        spin_unlock_irqrestore(&ring->lock, flags);
+
+       return released;
+}
+
+static int bcmgenet_tx_poll(struct napi_struct *napi, int budget)
+{
+       struct bcmgenet_tx_ring *ring =
+               container_of(napi, struct bcmgenet_tx_ring, napi);
+       unsigned int work_done = 0;
+
+       work_done = bcmgenet_tx_reclaim(ring->priv->dev, ring);
+
+       if (work_done == 0) {
+               napi_complete(napi);
+               ring->int_enable(ring->priv, ring);
+
+               return 0;
+       }
+
+       return budget;
 }
 
 static void bcmgenet_tx_reclaim_all(struct net_device *dev)
@@ -1302,10 +1329,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
        bcmgenet_tdma_ring_writel(priv, ring->index,
                                  ring->prod_index, TDMA_PROD_INDEX);
 
-       if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) {
+       if (ring->free_bds <= (MAX_SKB_FRAGS + 1))
                netif_tx_stop_queue(txq);
-               ring->int_enable(priv, ring);
-       }
 
 out:
        spin_unlock_irqrestore(&ring->lock, flags);
@@ -1621,6 +1646,7 @@ static int init_umac(struct bcmgenet_priv *priv)
        struct device *kdev = &priv->pdev->dev;
        int ret;
        u32 reg, cpu_mask_clear;
+       int index;
 
        dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n");
 
@@ -1647,7 +1673,7 @@ static int init_umac(struct bcmgenet_priv *priv)
 
        bcmgenet_intr_disable(priv);
 
-       cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE;
+       cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_TXDMA_BDONE;
 
        dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__);
 
@@ -1674,6 +1700,10 @@ static int init_umac(struct bcmgenet_priv *priv)
 
        bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR);
 
+       for (index = 0; index < priv->hw_params->tx_queues; index++)
+               bcmgenet_intrl2_1_writel(priv, (1 << index),
+                                        INTRL2_CPU_MASK_CLEAR);
+
        /* Enable rx/tx engine.*/
        dev_dbg(kdev, "done init umac\n");
 
@@ -1693,6 +1723,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
        unsigned int first_bd;
 
        spin_lock_init(&ring->lock);
+       ring->priv = priv;
+       netif_napi_add(priv->dev, &ring->napi, bcmgenet_tx_poll, 64);
        ring->index = index;
        if (index == DESC_INDEX) {
                ring->queue = 0;
@@ -1738,6 +1770,17 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
                                  TDMA_WRITE_PTR);
        bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1,
                                  DMA_END_ADDR);
+
+       napi_enable(&ring->napi);
+}
+
+static void bcmgenet_fini_tx_ring(struct bcmgenet_priv *priv,
+                                 unsigned int index)
+{
+       struct bcmgenet_tx_ring *ring = &priv->tx_rings[index];
+
+       napi_disable(&ring->napi);
+       netif_napi_del(&ring->napi);
 }
 
 /* Initialize a RDMA ring */
@@ -1907,7 +1950,7 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv)
        return ret;
 }
 
-static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
+static void __bcmgenet_fini_dma(struct bcmgenet_priv *priv)
 {
        int i;
 
@@ -1926,6 +1969,18 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
        kfree(priv->tx_cbs);
 }
 
+static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
+{
+       int i;
+
+       bcmgenet_fini_tx_ring(priv, DESC_INDEX);
+
+       for (i = 0; i < priv->hw_params->tx_queues; i++)
+               bcmgenet_fini_tx_ring(priv, i);
+
+       __bcmgenet_fini_dma(priv);
+}
+
 /* init_edma: Initialize DMA control register */
 static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
 {
@@ -1952,7 +2007,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
        priv->tx_cbs = kcalloc(priv->num_tx_bds, sizeof(struct enet_cb),
                               GFP_KERNEL);
        if (!priv->tx_cbs) {
-               bcmgenet_fini_dma(priv);
+               __bcmgenet_fini_dma(priv);
                return -ENOMEM;
        }
 
@@ -1975,9 +2030,6 @@ static int bcmgenet_poll(struct napi_struct *napi, int budget)
                        struct bcmgenet_priv, napi);
        unsigned int work_done;
 
-       /* tx reclaim */
-       bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
-
        work_done = bcmgenet_desc_rx(priv, budget);
 
        /* Advancing our consumer index*/
@@ -2022,28 +2074,34 @@ static void bcmgenet_irq_task(struct work_struct *work)
 static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
 {
        struct bcmgenet_priv *priv = dev_id;
+       struct bcmgenet_tx_ring *ring;
        unsigned int index;
 
        /* Save irq status for bottom-half processing. */
        priv->irq1_stat =
                bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
-               ~priv->int1_mask;
+               ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
        /* clear interrupts */
        bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
 
        netif_dbg(priv, intr, priv->dev,
                  "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
+
        /* Check the MBDONE interrupts.
         * packet is done, reclaim descriptors
         */
-       if (priv->irq1_stat & 0x0000ffff) {
-               index = 0;
-               for (index = 0; index < 16; index++) {
-                       if (priv->irq1_stat & (1 << index))
-                               bcmgenet_tx_reclaim(priv->dev,
-                                                   &priv->tx_rings[index]);
+       for (index = 0; index < priv->hw_params->tx_queues; index++) {
+               if (!(priv->irq1_stat & BIT(index)))
+                       continue;
+
+               ring = &priv->tx_rings[index];
+
+               if (likely(napi_schedule_prep(&ring->napi))) {
+                       ring->int_disable(priv, ring);
+                       __napi_schedule(&ring->napi);
                }
        }
+
        return IRQ_HANDLED;
 }
 
@@ -2075,8 +2133,12 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
        }
        if (priv->irq0_stat &
                        (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE)) {
-               /* Tx reclaim */
-               bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
+               struct bcmgenet_tx_ring *ring = &priv->tx_rings[DESC_INDEX];
+
+               if (likely(napi_schedule_prep(&ring->napi))) {
+                       ring->int_disable(priv, ring);
+                       __napi_schedule(&ring->napi);
+               }
        }
        if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R |
                                UMAC_IRQ_PHY_DET_F |
index b36ddec..0d370d1 100644 (file)
@@ -520,6 +520,7 @@ struct bcmgenet_hw_params {
 
 struct bcmgenet_tx_ring {
        spinlock_t      lock;           /* ring lock */
+       struct napi_struct napi;        /* NAPI per tx queue */
        unsigned int    index;          /* ring index */
        unsigned int    queue;          /* queue index */
        struct enet_cb  *cbs;           /* tx ring buffer control block*/
@@ -534,6 +535,7 @@ struct bcmgenet_tx_ring {
                           struct bcmgenet_tx_ring *);
        void (*int_disable)(struct bcmgenet_priv *priv,
                            struct bcmgenet_tx_ring *);
+       struct bcmgenet_priv *priv;
 };
 
 /* device context */
index 149a0d7..b971229 100644 (file)
@@ -73,15 +73,17 @@ int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
                return -EINVAL;
 
+       reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
        if (wol->wolopts & WAKE_MAGICSECURE) {
                bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
                                     UMAC_MPD_PW_MS);
                bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
                                     UMAC_MPD_PW_LS);
-               reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
                reg |= MPD_PW_EN;
-               bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+       } else {
+               reg &= ~MPD_PW_EN;
        }
+       bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
        /* Flag the device and relevant IRQ as wakeup capable */
        if (wol->wolopts) {
index ad76b8e..81d4153 100644 (file)
@@ -2113,17 +2113,17 @@ static const struct net_device_ops macb_netdev_ops = {
 };
 
 #if defined(CONFIG_OF)
-static struct macb_config pc302gem_config = {
+static const struct macb_config pc302gem_config = {
        .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
        .dma_burst_length = 16,
 };
 
-static struct macb_config sama5d3_config = {
+static const struct macb_config sama5d3_config = {
        .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
        .dma_burst_length = 16,
 };
 
-static struct macb_config sama5d4_config = {
+static const struct macb_config sama5d4_config = {
        .caps = 0,
        .dma_burst_length = 4,
 };
@@ -2154,7 +2154,7 @@ static void macb_configure_caps(struct macb *bp)
        if (bp->pdev->dev.of_node) {
                match = of_match_node(macb_dt_ids, bp->pdev->dev.of_node);
                if (match && match->data) {
-                       config = (const struct macb_config *)match->data;
+                       config = match->data;
 
                        bp->caps = config->caps;
                        /*
index 31dc080..ff85619 100644 (file)
 
 /* Bitfields in MID */
 #define MACB_IDNUM_OFFSET                      16
-#define MACB_IDNUM_SIZE                                16
+#define MACB_IDNUM_SIZE                                12
 #define MACB_REV_OFFSET                                0
 #define MACB_REV_SIZE                          16
 
index 9062a84..c308429 100644 (file)
@@ -35,10 +35,10 @@ static inline unsigned int ipv6_clip_hash(struct clip_tbl *d, const u32 *key)
 }
 
 static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr,
-                                  int addr_len)
+                                  u8 v6)
 {
-       return addr_len == 4 ? ipv4_clip_hash(ctbl, addr) :
-                               ipv6_clip_hash(ctbl, addr);
+       return v6 ? ipv6_clip_hash(ctbl, addr) :
+                       ipv4_clip_hash(ctbl, addr);
 }
 
 static int clip6_get_mbox(const struct net_device *dev,
@@ -78,23 +78,22 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
        struct clip_entry *ce, *cte;
        u32 *addr = (u32 *)lip;
        int hash;
-       int addr_len;
-       int ret = 0;
+       int ret = -1;
 
        if (!ctbl)
                return 0;
 
-       if (v6)
-               addr_len = 16;
-       else
-               addr_len = 4;
-
-       hash = clip_addr_hash(ctbl, addr, addr_len);
+       hash = clip_addr_hash(ctbl, addr, v6);
 
        read_lock_bh(&ctbl->lock);
        list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
-               if (addr_len == cte->addr_len &&
-                   memcmp(lip, cte->addr, cte->addr_len) == 0) {
+               if (cte->addr6.sin6_family == AF_INET6 && v6)
+                       ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
+                                    sizeof(struct in6_addr));
+               else if (cte->addr.sin_family == AF_INET && !v6)
+                       ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
+                                    sizeof(struct in_addr));
+               if (!ret) {
                        ce = cte;
                        read_unlock_bh(&ctbl->lock);
                        goto found;
@@ -111,15 +110,20 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
                spin_lock_init(&ce->lock);
                atomic_set(&ce->refcnt, 0);
                atomic_dec(&ctbl->nfree);
-               ce->addr_len = addr_len;
-               memcpy(ce->addr, lip, addr_len);
                list_add_tail(&ce->list, &ctbl->hash_list[hash]);
                if (v6) {
+                       ce->addr6.sin6_family = AF_INET6;
+                       memcpy(ce->addr6.sin6_addr.s6_addr,
+                              lip, sizeof(struct in6_addr));
                        ret = clip6_get_mbox(dev, (const struct in6_addr *)lip);
                        if (ret) {
                                write_unlock_bh(&ctbl->lock);
                                return ret;
                        }
+               } else {
+                       ce->addr.sin_family = AF_INET;
+                       memcpy((char *)(&ce->addr.sin_addr), lip,
+                              sizeof(struct in_addr));
                }
        } else {
                write_unlock_bh(&ctbl->lock);
@@ -140,19 +144,19 @@ void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
        struct clip_entry *ce, *cte;
        u32 *addr = (u32 *)lip;
        int hash;
-       int addr_len;
-
-       if (v6)
-               addr_len = 16;
-       else
-               addr_len = 4;
+       int ret = -1;
 
-       hash = clip_addr_hash(ctbl, addr, addr_len);
+       hash = clip_addr_hash(ctbl, addr, v6);
 
        read_lock_bh(&ctbl->lock);
        list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
-               if (addr_len == cte->addr_len &&
-                   memcmp(lip, cte->addr, cte->addr_len) == 0) {
+               if (cte->addr6.sin6_family == AF_INET6 && v6)
+                       ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
+                                    sizeof(struct in6_addr));
+               else if (cte->addr.sin_family == AF_INET && !v6)
+                       ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
+                                    sizeof(struct in_addr));
+               if (!ret) {
                        ce = cte;
                        read_unlock_bh(&ctbl->lock);
                        goto found;
@@ -249,10 +253,7 @@ int clip_tbl_show(struct seq_file *seq, void *v)
        for (i = 0 ; i < ctbl->clipt_size;  ++i) {
                list_for_each_entry(ce, &ctbl->hash_list[i], list) {
                        ip[0] = '\0';
-                       if (ce->addr_len == 16)
-                               sprintf(ip, "%pI6c", ce->addr);
-                       else
-                               sprintf(ip, "%pI4c", ce->addr);
+                       sprintf(ip, "%pISc", &ce->addr);
                        seq_printf(seq, "%-25s   %u\n", ip,
                                   atomic_read(&ce->refcnt));
                }
index 2eaba01..35eb43c 100644 (file)
@@ -14,8 +14,10 @@ struct clip_entry {
        spinlock_t lock;        /* Hold while modifying clip reference */
        atomic_t refcnt;
        struct list_head list;
-       u32 addr[4];
-       int addr_len;
+       union {
+               struct sockaddr_in addr;
+               struct sockaddr_in6 addr6;
+       };
 };
 
 struct clip_tbl {
index d6cda17..c6ff489 100644 (file)
@@ -376,8 +376,6 @@ enum {
 enum {
        INGQ_EXTRAS = 2,        /* firmware event queue and */
                                /*   forwarded interrupts */
-       MAX_EGRQ = MAX_ETH_QSETS*2 + MAX_OFLD_QSETS*2
-                  + MAX_CTRL_QUEUES + MAX_RDMA_QUEUES + MAX_ISCSI_QUEUES,
        MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES
                   + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS,
 };
@@ -616,11 +614,13 @@ struct sge {
        unsigned int idma_qid[2];   /* SGE IDMA Hung Ingress Queue ID */
 
        unsigned int egr_start;
+       unsigned int egr_sz;
        unsigned int ingr_start;
-       void *egr_map[MAX_EGRQ];    /* qid->queue egress queue map */
-       struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */
-       DECLARE_BITMAP(starving_fl, MAX_EGRQ);
-       DECLARE_BITMAP(txq_maperr, MAX_EGRQ);
+       unsigned int ingr_sz;
+       void **egr_map;    /* qid->queue egress queue map */
+       struct sge_rspq **ingr_map; /* qid->queue ingress queue map */
+       unsigned long *starving_fl;
+       unsigned long *txq_maperr;
        struct timer_list rx_timer; /* refills starving FLs */
        struct timer_list tx_timer; /* checks Tx queues */
 };
@@ -1103,7 +1103,7 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
 #define T4_MEMORY_WRITE        0
 #define T4_MEMORY_READ 1
 int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, u32 len,
-                __be32 *buf, int dir);
+                void *buf, int dir);
 static inline int t4_memory_write(struct adapter *adap, int mtype, u32 addr,
                                  u32 len, __be32 *buf)
 {
@@ -1136,6 +1136,8 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
 
 unsigned int qtimer_val(const struct adapter *adap,
                        const struct sge_rspq *q);
+
+int t4_init_devlog_params(struct adapter *adapter);
 int t4_init_sge_params(struct adapter *adapter);
 int t4_init_tp_params(struct adapter *adap);
 int t4_filter_field_shift(const struct adapter *adap, int filter_sel);
index 78854ce..dcb0479 100644 (file)
@@ -670,9 +670,13 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v)
                "0.9375" };
 
        int i;
-       u16 incr[NMTUS][NCCTRL_WIN];
+       u16 (*incr)[NCCTRL_WIN];
        struct adapter *adap = seq->private;
 
+       incr = kmalloc(sizeof(*incr) * NMTUS, GFP_KERNEL);
+       if (!incr)
+               return -ENOMEM;
+
        t4_read_cong_tbl(adap, incr);
 
        for (i = 0; i < NCCTRL_WIN; ++i) {
@@ -685,6 +689,8 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v)
                           adap->params.a_wnd[i],
                           dec_fac[adap->params.b_wnd[i]]);
        }
+
+       kfree(incr);
        return 0;
 }
 
index a22cf93..d929951 100644 (file)
@@ -920,7 +920,7 @@ static void quiesce_rx(struct adapter *adap)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
+       for (i = 0; i < adap->sge.ingr_sz; i++) {
                struct sge_rspq *q = adap->sge.ingr_map[i];
 
                if (q && q->handler) {
@@ -934,6 +934,21 @@ static void quiesce_rx(struct adapter *adap)
        }
 }
 
+/* Disable interrupt and napi handler */
+static void disable_interrupts(struct adapter *adap)
+{
+       if (adap->flags & FULL_INIT_DONE) {
+               t4_intr_disable(adap);
+               if (adap->flags & USING_MSIX) {
+                       free_msix_queue_irqs(adap);
+                       free_irq(adap->msix_info[0].vec, adap);
+               } else {
+                       free_irq(adap->pdev->irq, adap);
+               }
+               quiesce_rx(adap);
+       }
+}
+
 /*
  * Enable NAPI scheduling and interrupt generation for all Rx queues.
  */
@@ -941,7 +956,7 @@ static void enable_rx(struct adapter *adap)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
+       for (i = 0; i < adap->sge.ingr_sz; i++) {
                struct sge_rspq *q = adap->sge.ingr_map[i];
 
                if (!q)
@@ -970,8 +985,8 @@ static int setup_sge_queues(struct adapter *adap)
        int err, msi_idx, i, j;
        struct sge *s = &adap->sge;
 
-       bitmap_zero(s->starving_fl, MAX_EGRQ);
-       bitmap_zero(s->txq_maperr, MAX_EGRQ);
+       bitmap_zero(s->starving_fl, s->egr_sz);
+       bitmap_zero(s->txq_maperr, s->egr_sz);
 
        if (adap->flags & USING_MSIX)
                msi_idx = 1;         /* vector 0 is for non-queue interrupts */
@@ -983,6 +998,19 @@ static int setup_sge_queues(struct adapter *adap)
                msi_idx = -((int)s->intrq.abs_id + 1);
        }
 
+       /* NOTE: If you add/delete any Ingress/Egress Queue allocations in here,
+        * don't forget to update the following which need to be
+        * synchronized to and changes here.
+        *
+        * 1. The calculations of MAX_INGQ in cxgb4.h.
+        *
+        * 2. Update enable_msix/name_msix_vecs/request_msix_queue_irqs
+        *    to accommodate any new/deleted Ingress Queues
+        *    which need MSI-X Vectors.
+        *
+        * 3. Update sge_qinfo_show() to include information on the
+        *    new/deleted queues.
+        */
        err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0],
                               msi_idx, NULL, fwevtq_handler);
        if (err) {
@@ -4244,19 +4272,12 @@ static int cxgb_up(struct adapter *adap)
 
 static void cxgb_down(struct adapter *adapter)
 {
-       t4_intr_disable(adapter);
        cancel_work_sync(&adapter->tid_release_task);
        cancel_work_sync(&adapter->db_full_task);
        cancel_work_sync(&adapter->db_drop_task);
        adapter->tid_release_task_busy = false;
        adapter->tid_release_head = NULL;
 
-       if (adapter->flags & USING_MSIX) {
-               free_msix_queue_irqs(adapter);
-               free_irq(adapter->msix_info[0].vec, adapter);
-       } else
-               free_irq(adapter->pdev->irq, adapter);
-       quiesce_rx(adapter);
        t4_sge_stop(adapter);
        t4_free_sge_resources(adapter);
        adapter->flags &= ~FULL_INIT_DONE;
@@ -4733,8 +4754,9 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
        if (ret < 0)
                return ret;
 
-       ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ,
-                         0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF);
+       ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, adap->sge.egr_sz, 64,
+                         MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF,
+                         FW_CMD_CAP_PF);
        if (ret < 0)
                return ret;
 
@@ -5088,10 +5110,15 @@ static int adap_init0(struct adapter *adap)
        enum dev_state state;
        u32 params[7], val[7];
        struct fw_caps_config_cmd caps_cmd;
-       struct fw_devlog_cmd devlog_cmd;
-       u32 devlog_meminfo;
        int reset = 1;
 
+       /* Grab Firmware Device Log parameters as early as possible so we have
+        * access to it for debugging, etc.
+        */
+       ret = t4_init_devlog_params(adap);
+       if (ret < 0)
+               return ret;
+
        /* Contact FW, advertising Master capability */
        ret = t4_fw_hello(adap, adap->mbox, adap->mbox, MASTER_MAY, &state);
        if (ret < 0) {
@@ -5169,30 +5196,6 @@ static int adap_init0(struct adapter *adap)
        if (ret < 0)
                goto bye;
 
-       /* Read firmware device log parameters.  We really need to find a way
-        * to get these parameters initialized with some default values (which
-        * are likely to be correct) for the case where we either don't
-        * attache to the firmware or it's crashed when we probe the adapter.
-        * That way we'll still be able to perform early firmware startup
-        * debugging ...  If the request to get the Firmware's Device Log
-        * parameters fails, we'll live so we don't make that a fatal error.
-        */
-       memset(&devlog_cmd, 0, sizeof(devlog_cmd));
-       devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
-                                      FW_CMD_REQUEST_F | FW_CMD_READ_F);
-       devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
-       ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
-                        &devlog_cmd);
-       if (ret == 0) {
-               devlog_meminfo =
-                       ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
-               adap->params.devlog.memtype =
-                       FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
-               adap->params.devlog.start =
-                       FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
-               adap->params.devlog.size = ntohl(devlog_cmd.memsize_devlog);
-       }
-
        /*
         * Find out what ports are available to us.  Note that we need to do
         * this before calling adap_init0_no_config() since it needs nports
@@ -5293,6 +5296,51 @@ static int adap_init0(struct adapter *adap)
        adap->tids.nftids = val[4] - val[3] + 1;
        adap->sge.ingr_start = val[5];
 
+       /* qids (ingress/egress) returned from firmware can be anywhere
+        * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END.
+        * Hence driver needs to allocate memory for this range to
+        * store the queue info. Get the highest IQFLINT/EQ index returned
+        * in FW_EQ_*_CMD.alloc command.
+        */
+       params[0] = FW_PARAM_PFVF(EQ_END);
+       params[1] = FW_PARAM_PFVF(IQFLINT_END);
+       ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
+       if (ret < 0)
+               goto bye;
+       adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1;
+       adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1;
+
+       adap->sge.egr_map = kcalloc(adap->sge.egr_sz,
+                                   sizeof(*adap->sge.egr_map), GFP_KERNEL);
+       if (!adap->sge.egr_map) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz,
+                                    sizeof(*adap->sge.ingr_map), GFP_KERNEL);
+       if (!adap->sge.ingr_map) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       /* Allocate the memory for the vaious egress queue bitmaps
+        * ie starving_fl and txq_maperr.
+        */
+       adap->sge.starving_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
+                                       sizeof(long), GFP_KERNEL);
+       if (!adap->sge.starving_fl) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       adap->sge.txq_maperr = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
+                                      sizeof(long), GFP_KERNEL);
+       if (!adap->sge.txq_maperr) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
        params[0] = FW_PARAM_PFVF(CLIP_START);
        params[1] = FW_PARAM_PFVF(CLIP_END);
        ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
@@ -5501,6 +5549,10 @@ static int adap_init0(struct adapter *adap)
         * happened to HW/FW, stop issuing commands.
         */
 bye:
+       kfree(adap->sge.egr_map);
+       kfree(adap->sge.ingr_map);
+       kfree(adap->sge.starving_fl);
+       kfree(adap->sge.txq_maperr);
        if (ret != -ETIMEDOUT && ret != -EIO)
                t4_fw_bye(adap, adap->mbox);
        return ret;
@@ -5528,6 +5580,7 @@ static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
                netif_carrier_off(dev);
        }
        spin_unlock(&adap->stats_lock);
+       disable_interrupts(adap);
        if (adap->flags & FULL_INIT_DONE)
                cxgb_down(adap);
        rtnl_unlock();
@@ -5912,6 +5965,10 @@ static void free_some_resources(struct adapter *adapter)
 
        t4_free_mem(adapter->l2t);
        t4_free_mem(adapter->tids.tid_tab);
+       kfree(adapter->sge.egr_map);
+       kfree(adapter->sge.ingr_map);
+       kfree(adapter->sge.starving_fl);
+       kfree(adapter->sge.txq_maperr);
        disable_msi(adapter);
 
        for_each_port(adapter, i)
@@ -6237,6 +6294,8 @@ static void remove_one(struct pci_dev *pdev)
                if (is_offload(adapter))
                        detach_ulds(adapter);
 
+               disable_interrupts(adapter);
+
                for_each_port(adapter, i)
                        if (adapter->port[i]->reg_state == NETREG_REGISTERED)
                                unregister_netdev(adapter->port[i]);
index b4b9f60..b688b32 100644 (file)
@@ -2171,7 +2171,7 @@ static void sge_rx_timer_cb(unsigned long data)
        struct adapter *adap = (struct adapter *)data;
        struct sge *s = &adap->sge;
 
-       for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++)
+       for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
                for (m = s->starving_fl[i]; m; m &= m - 1) {
                        struct sge_eth_rxq *rxq;
                        unsigned int id = __ffs(m) + i * BITS_PER_LONG;
@@ -2259,7 +2259,7 @@ static void sge_tx_timer_cb(unsigned long data)
        struct adapter *adap = (struct adapter *)data;
        struct sge *s = &adap->sge;
 
-       for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++)
+       for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
                for (m = s->txq_maperr[i]; m; m &= m - 1) {
                        unsigned long id = __ffs(m) + i * BITS_PER_LONG;
                        struct sge_ofld_txq *txq = s->egr_map[id];
@@ -2741,7 +2741,8 @@ void t4_free_sge_resources(struct adapter *adap)
                free_rspq_fl(adap, &adap->sge.intrq, NULL);
 
        /* clear the reverse egress queue map */
-       memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map));
+       memset(adap->sge.egr_map, 0,
+              adap->sge.egr_sz * sizeof(*adap->sge.egr_map));
 }
 
 void t4_sge_start(struct adapter *adap)
index 4d643b6..ee394dc 100644 (file)
@@ -449,7 +449,7 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
  *     @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
  *     @addr: address within indicated memory type
  *     @len: amount of memory to transfer
- *     @buf: host memory buffer
+ *     @hbuf: host memory buffer
  *     @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0)
  *
  *     Reads/writes an [almost] arbitrary memory region in the firmware: the
@@ -460,15 +460,17 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
  *     caller's responsibility to perform appropriate byte order conversions.
  */
 int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
-                u32 len, __be32 *buf, int dir)
+                u32 len, void *hbuf, int dir)
 {
        u32 pos, offset, resid, memoffset;
        u32 edc_size, mc_size, win_pf, mem_reg, mem_aperture, mem_base;
+       u32 *buf;
 
        /* Argument sanity checks ...
         */
-       if (addr & 0x3)
+       if (addr & 0x3 || (uintptr_t)hbuf & 0x3)
                return -EINVAL;
+       buf = (u32 *)hbuf;
 
        /* It's convenient to be able to handle lengths which aren't a
         * multiple of 32-bits because we often end up transferring files to
@@ -532,14 +534,45 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
 
        /* Transfer data to/from the adapter as long as there's an integral
         * number of 32-bit transfers to complete.
+        *
+        * A note on Endianness issues:
+        *
+        * The "register" reads and writes below from/to the PCI-E Memory
+        * Window invoke the standard adapter Big-Endian to PCI-E Link
+        * Little-Endian "swizzel."  As a result, if we have the following
+        * data in adapter memory:
+        *
+        *     Memory:  ... | b0 | b1 | b2 | b3 | ...
+        *     Address:      i+0  i+1  i+2  i+3
+        *
+        * Then a read of the adapter memory via the PCI-E Memory Window
+        * will yield:
+        *
+        *     x = readl(i)
+        *         31                  0
+        *         [ b3 | b2 | b1 | b0 ]
+        *
+        * If this value is stored into local memory on a Little-Endian system
+        * it will show up correctly in local memory as:
+        *
+        *     ( ..., b0, b1, b2, b3, ... )
+        *
+        * But on a Big-Endian system, the store will show up in memory
+        * incorrectly swizzled as:
+        *
+        *     ( ..., b3, b2, b1, b0, ... )
+        *
+        * So we need to account for this in the reads and writes to the
+        * PCI-E Memory Window below by undoing the register read/write
+        * swizzels.
         */
        while (len > 0) {
                if (dir == T4_MEMORY_READ)
-                       *buf++ = (__force __be32) t4_read_reg(adap,
-                                                       mem_base + offset);
+                       *buf++ = le32_to_cpu((__force __le32)t4_read_reg(adap,
+                                               mem_base + offset));
                else
                        t4_write_reg(adap, mem_base + offset,
-                                    (__force u32) *buf++);
+                                    (__force u32)cpu_to_le32(*buf++));
                offset += sizeof(__be32);
                len -= sizeof(__be32);
 
@@ -568,15 +601,16 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
         */
        if (resid) {
                union {
-                       __be32 word;
+                       u32 word;
                        char byte[4];
                } last;
                unsigned char *bp;
                int i;
 
                if (dir == T4_MEMORY_READ) {
-                       last.word = (__force __be32) t4_read_reg(adap,
-                                                       mem_base + offset);
+                       last.word = le32_to_cpu(
+                                       (__force __le32)t4_read_reg(adap,
+                                               mem_base + offset));
                        for (bp = (unsigned char *)buf, i = resid; i < 4; i++)
                                bp[i] = last.byte[i];
                } else {
@@ -584,7 +618,7 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
                        for (i = resid; i < 4; i++)
                                last.byte[i] = 0;
                        t4_write_reg(adap, mem_base + offset,
-                                    (__force u32) last.word);
+                                    (__force u32)cpu_to_le32(last.word));
                }
        }
 
@@ -1086,7 +1120,7 @@ int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info,
                }
 
                /* Installed successfully, update the cached header too. */
-               memcpy(card_fw, fs_fw, sizeof(*card_fw));
+               *card_fw = *fs_fw;
                card_fw_usable = 1;
                *reset = 0;     /* already reset as part of load_fw */
        }
@@ -4424,6 +4458,59 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
        return 0;
 }
 
+/**
+ *     t4_init_devlog_params - initialize adapter->params.devlog
+ *     @adap: the adapter
+ *
+ *     Initialize various fields of the adapter's Firmware Device Log
+ *     Parameters structure.
+ */
+int t4_init_devlog_params(struct adapter *adap)
+{
+       struct devlog_params *dparams = &adap->params.devlog;
+       u32 pf_dparams;
+       unsigned int devlog_meminfo;
+       struct fw_devlog_cmd devlog_cmd;
+       int ret;
+
+       /* If we're dealing with newer firmware, the Device Log Paramerters
+        * are stored in a designated register which allows us to access the
+        * Device Log even if we can't talk to the firmware.
+        */
+       pf_dparams =
+               t4_read_reg(adap, PCIE_FW_REG(PCIE_FW_PF_A, PCIE_FW_PF_DEVLOG));
+       if (pf_dparams) {
+               unsigned int nentries, nentries128;
+
+               dparams->memtype = PCIE_FW_PF_DEVLOG_MEMTYPE_G(pf_dparams);
+               dparams->start = PCIE_FW_PF_DEVLOG_ADDR16_G(pf_dparams) << 4;
+
+               nentries128 = PCIE_FW_PF_DEVLOG_NENTRIES128_G(pf_dparams);
+               nentries = (nentries128 + 1) * 128;
+               dparams->size = nentries * sizeof(struct fw_devlog_e);
+
+               return 0;
+       }
+
+       /* Otherwise, ask the firmware for it's Device Log Parameters.
+        */
+       memset(&devlog_cmd, 0, sizeof(devlog_cmd));
+       devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
+                                      FW_CMD_REQUEST_F | FW_CMD_READ_F);
+       devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
+       ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
+                        &devlog_cmd);
+       if (ret)
+               return ret;
+
+       devlog_meminfo = ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
+       dparams->memtype = FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
+       dparams->start = FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
+       dparams->size = ntohl(devlog_cmd.memsize_devlog);
+
+       return 0;
+}
+
 /**
  *     t4_init_sge_params - initialize adap->params.sge
  *     @adapter: the adapter
index 231a725..326674b 100644 (file)
@@ -63,6 +63,8 @@
 #define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
 #define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
 
+#define PCIE_FW_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
+
 #define SGE_PF_KDOORBELL_A 0x0
 
 #define QID_S    15
 #define PFNUM_V(x) ((x) << PFNUM_S)
 
 #define PCIE_FW_A 0x30b8
+#define PCIE_FW_PF_A 0x30bc
 
 #define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A 0x5908
 
index 9b353a8..a4a19e0 100644 (file)
@@ -101,7 +101,7 @@ enum fw_wr_opcodes {
        FW_RI_BIND_MW_WR               = 0x18,
        FW_RI_FR_NSMR_WR               = 0x19,
        FW_RI_INV_LSTAG_WR             = 0x1a,
-       FW_LASTC2E_WR                  = 0x40
+       FW_LASTC2E_WR                  = 0x70
 };
 
 struct fw_wr_hdr {
@@ -993,6 +993,7 @@ enum fw_memtype_cf {
        FW_MEMTYPE_CF_EXTMEM            = 0x2,
        FW_MEMTYPE_CF_FLASH             = 0x4,
        FW_MEMTYPE_CF_INTERNAL          = 0x5,
+       FW_MEMTYPE_CF_EXTMEM1           = 0x6,
 };
 
 struct fw_caps_config_cmd {
@@ -1035,6 +1036,7 @@ enum fw_params_mnem {
        FW_PARAMS_MNEM_PFVF             = 2,    /* function params */
        FW_PARAMS_MNEM_REG              = 3,    /* limited register access */
        FW_PARAMS_MNEM_DMAQ             = 4,    /* dma queue params */
+       FW_PARAMS_MNEM_CHNET            = 5,    /* chnet params */
        FW_PARAMS_MNEM_LAST
 };
 
@@ -3102,7 +3104,8 @@ enum fw_devlog_facility {
        FW_DEVLOG_FACILITY_FCOE         = 0x2E,
        FW_DEVLOG_FACILITY_FOISCSI      = 0x30,
        FW_DEVLOG_FACILITY_FOFCOE       = 0x32,
-       FW_DEVLOG_FACILITY_MAX          = 0x32,
+       FW_DEVLOG_FACILITY_CHNET        = 0x34,
+       FW_DEVLOG_FACILITY_MAX          = 0x34,
 };
 
 /* log message format */
@@ -3139,4 +3142,36 @@ struct fw_devlog_cmd {
        (((x) >> FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S) & \
         FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M)
 
+/* P C I E   F W   P F 7   R E G I S T E R */
+
+/* PF7 stores the Firmware Device Log parameters which allows Host Drivers to
+ * access the "devlog" which needing to contact firmware.  The encoding is
+ * mostly the same as that returned by the DEVLOG command except for the size
+ * which is encoded as the number of entries in multiples-1 of 128 here rather
+ * than the memory size as is done in the DEVLOG command.  Thus, 0 means 128
+ * and 15 means 2048.  This of course in turn constrains the allowed values
+ * for the devlog size ...
+ */
+#define PCIE_FW_PF_DEVLOG              7
+
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_S        28
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_M        0xf
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_V(x) \
+       ((x) << PCIE_FW_PF_DEVLOG_NENTRIES128_S)
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_NENTRIES128_S) & \
+        PCIE_FW_PF_DEVLOG_NENTRIES128_M)
+
+#define PCIE_FW_PF_DEVLOG_ADDR16_S     4
+#define PCIE_FW_PF_DEVLOG_ADDR16_M     0xffffff
+#define PCIE_FW_PF_DEVLOG_ADDR16_V(x)  ((x) << PCIE_FW_PF_DEVLOG_ADDR16_S)
+#define PCIE_FW_PF_DEVLOG_ADDR16_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_ADDR16_S) & PCIE_FW_PF_DEVLOG_ADDR16_M)
+
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_S    0
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_M    0xf
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_V(x) ((x) << PCIE_FW_PF_DEVLOG_MEMTYPE_S)
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_MEMTYPE_S) & PCIE_FW_PF_DEVLOG_MEMTYPE_M)
+
 #endif /* _T4FW_INTERFACE_H_ */
index e2bd3f7..b9d1cba 100644 (file)
 #define __T4FW_VERSION_H__
 
 #define T4FW_VERSION_MAJOR 0x01
-#define T4FW_VERSION_MINOR 0x0C
-#define T4FW_VERSION_MICRO 0x19
+#define T4FW_VERSION_MINOR 0x0D
+#define T4FW_VERSION_MICRO 0x20
 #define T4FW_VERSION_BUILD 0x00
 
 #define T5FW_VERSION_MAJOR 0x01
-#define T5FW_VERSION_MINOR 0x0C
-#define T5FW_VERSION_MICRO 0x19
+#define T5FW_VERSION_MINOR 0x0D
+#define T5FW_VERSION_MICRO 0x20
 #define T5FW_VERSION_BUILD 0x00
 
 #endif
index 0545f0d..e0d7110 100644 (file)
@@ -1004,7 +1004,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
                                              ? (tq->pidx - 1)
                                              : (tq->size - 1));
                        __be64 *src = (__be64 *)&tq->desc[index];
-                       __be64 __iomem *dst = (__be64 *)(tq->bar2_addr +
+                       __be64 __iomem *dst = (__be64 __iomem *)(tq->bar2_addr +
                                                         SGE_UDB_WCDOORBELL);
                        unsigned int count = EQ_UNIT / sizeof(__be64);
 
@@ -1018,7 +1018,11 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
                         * DMA.
                         */
                        while (count) {
-                               writeq(*src, dst);
+                               /* the (__force u64) is because the compiler
+                                * doesn't understand the endian swizzling
+                                * going on
+                                */
+                               writeq((__force u64)*src, dst);
                                src++;
                                dst++;
                                count--;
@@ -1252,8 +1256,8 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1);
        wr = (void *)&txq->q.desc[txq->q.pidx];
        wr->equiq_to_len16 = cpu_to_be32(wr_mid);
-       wr->r3[0] = cpu_to_be64(0);
-       wr->r3[1] = cpu_to_be64(0);
+       wr->r3[0] = cpu_to_be32(0);
+       wr->r3[1] = cpu_to_be32(0);
        skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len);
        end = (u64 *)wr + flits;
 
index 1b5506d..280b4a2 100644 (file)
@@ -210,10 +210,10 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
 
                        if (rpl) {
                                /* request bit in high-order BE word */
-                               WARN_ON((be32_to_cpu(*(const u32 *)cmd)
+                               WARN_ON((be32_to_cpu(*(const __be32 *)cmd)
                                         & FW_CMD_REQUEST_F) == 0);
                                get_mbox_rpl(adapter, rpl, size, mbox_data);
-                               WARN_ON((be32_to_cpu(*(u32 *)rpl)
+                               WARN_ON((be32_to_cpu(*(__be32 *)rpl)
                                         & FW_CMD_REQUEST_F) != 0);
                        }
                        t4_write_reg(adapter, mbox_ctl,
@@ -484,7 +484,7 @@ int t4_bar2_sge_qregs(struct adapter *adapter,
         *  o The BAR2 Queue ID.
         *  o The BAR2 Queue ID Offset into the BAR2 page.
         */
-       bar2_page_offset = ((qid >> qpp_shift) << page_shift);
+       bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift);
        bar2_qid = qid & qpp_mask;
        bar2_qid_offset = bar2_qid * SGE_UDB_SIZE;
 
index 9cbe038..a5179bf 100644 (file)
@@ -272,8 +272,8 @@ static irqreturn_t enic_isr_legacy(int irq, void *data)
        }
 
        if (ENIC_TEST_INTR(pba, notify_intr)) {
-               vnic_intr_return_all_credits(&enic->intr[notify_intr]);
                enic_notify_check(enic);
+               vnic_intr_return_all_credits(&enic->intr[notify_intr]);
        }
 
        if (ENIC_TEST_INTR(pba, err_intr)) {
@@ -346,8 +346,8 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data)
        struct enic *enic = data;
        unsigned int intr = enic_msix_notify_intr(enic);
 
-       vnic_intr_return_all_credits(&enic->intr[intr]);
        enic_notify_check(enic);
+       vnic_intr_return_all_credits(&enic->intr[intr]);
 
        return IRQ_HANDLED;
 }
index 3b42556..ed41559 100644 (file)
@@ -589,7 +589,7 @@ static void tulip_tx_timeout(struct net_device *dev)
                               (unsigned int)tp->rx_ring[i].buffer1,
                               (unsigned int)tp->rx_ring[i].buffer2,
                               buf[0], buf[1], buf[2]);
-                       for (j = 0; buf[j] != 0xee && j < 1600; j++)
+                       for (j = 0; ((j < 1600) && buf[j] != 0xee); j++)
                                if (j < 100)
                                        pr_cont(" %02x", buf[j]);
                        pr_cont(" j=%d\n", j);
index 27de37a..27b9fe9 100644 (file)
@@ -354,6 +354,7 @@ struct be_vf_cfg {
        u16 vlan_tag;
        u32 tx_rate;
        u32 plink_tracking;
+       u32 privileges;
 };
 
 enum vf_state {
@@ -423,6 +424,7 @@ struct be_adapter {
 
        u8 __iomem *csr;        /* CSR BAR used only for BE2/3 */
        u8 __iomem *db;         /* Door Bell */
+       u8 __iomem *pcicfg;     /* On SH,BEx only. Shadow of PCI config space */
 
        struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
        struct be_dma_mem mbox_mem;
index 36916cf..7f05f30 100644 (file)
@@ -1902,15 +1902,11 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
 {
        int num_eqs, i = 0;
 
-       if (lancer_chip(adapter) && num > 8) {
-               while (num) {
-                       num_eqs = min(num, 8);
-                       __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
-                       i += num_eqs;
-                       num -= num_eqs;
-               }
-       } else {
-               __be_cmd_modify_eqd(adapter, set_eqd, num);
+       while (num) {
+               num_eqs = min(num, 8);
+               __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
+               i += num_eqs;
+               num -= num_eqs;
        }
 
        return 0;
@@ -1918,7 +1914,7 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
 
 /* Uses sycnhronous mcc */
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num)
+                      u32 num, u32 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_vlan_config *req;
@@ -1936,6 +1932,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
        be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                               OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req),
                               wrb, NULL);
+       req->hdr.domain = domain;
 
        req->interface_id = if_id;
        req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0;
index db761e8..a7634a3 100644 (file)
@@ -2256,7 +2256,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
 int be_cmd_get_fw_ver(struct be_adapter *adapter);
 int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num);
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num);
+                      u32 num, u32 domain);
 int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
 int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc);
 int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc);
index 0a81685..e6b790f 100644 (file)
@@ -1171,7 +1171,7 @@ static int be_vid_config(struct be_adapter *adapter)
        for_each_set_bit(i, adapter->vids, VLAN_N_VID)
                vids[num++] = cpu_to_le16(i);
 
-       status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num);
+       status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num, 0);
        if (status) {
                dev_err(dev, "Setting HW VLAN filtering failed\n");
                /* Set to VLAN promisc mode as setting VLAN filter failed */
@@ -1380,11 +1380,67 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
        return 0;
 }
 
+static int be_set_vf_tvt(struct be_adapter *adapter, int vf, u16 vlan)
+{
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+       u16 vids[BE_NUM_VLANS_SUPPORTED];
+       int vf_if_id = vf_cfg->if_handle;
+       int status;
+
+       /* Enable Transparent VLAN Tagging */
+       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, vf_if_id, 0);
+       if (status)
+               return status;
+
+       /* Clear pre-programmed VLAN filters on VF if any, if TVT is enabled */
+       vids[0] = 0;
+       status = be_cmd_vlan_config(adapter, vf_if_id, vids, 1, vf + 1);
+       if (!status)
+               dev_info(&adapter->pdev->dev,
+                        "Cleared guest VLANs on VF%d", vf);
+
+       /* After TVT is enabled, disallow VFs to program VLAN filters */
+       if (vf_cfg->privileges & BE_PRIV_FILTMGMT) {
+               status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges &
+                                                 ~BE_PRIV_FILTMGMT, vf + 1);
+               if (!status)
+                       vf_cfg->privileges &= ~BE_PRIV_FILTMGMT;
+       }
+       return 0;
+}
+
+static int be_clear_vf_tvt(struct be_adapter *adapter, int vf)
+{
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+       struct device *dev = &adapter->pdev->dev;
+       int status;
+
+       /* Reset Transparent VLAN Tagging. */
+       status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID, vf + 1,
+                                      vf_cfg->if_handle, 0);
+       if (status)
+               return status;
+
+       /* Allow VFs to program VLAN filtering */
+       if (!(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
+               status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges |
+                                                 BE_PRIV_FILTMGMT, vf + 1);
+               if (!status) {
+                       vf_cfg->privileges |= BE_PRIV_FILTMGMT;
+                       dev_info(dev, "VF%d: FILTMGMT priv enabled", vf);
+               }
+       }
+
+       dev_info(dev,
+                "Disable/re-enable i/f in VM to clear Transparent VLAN tag");
+       return 0;
+}
+
 static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
-       int status = 0;
+       int status;
 
        if (!sriov_enabled(adapter))
                return -EPERM;
@@ -1394,24 +1450,19 @@ static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
 
        if (vlan || qos) {
                vlan |= qos << VLAN_PRIO_SHIFT;
-               if (vf_cfg->vlan_tag != vlan)
-                       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                                                      vf_cfg->if_handle, 0);
+               status = be_set_vf_tvt(adapter, vf, vlan);
        } else {
-               /* Reset Transparent Vlan Tagging. */
-               status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
-                                              vf + 1, vf_cfg->if_handle, 0);
+               status = be_clear_vf_tvt(adapter, vf);
        }
 
        if (status) {
                dev_err(&adapter->pdev->dev,
-                       "VLAN %d config on VF %d failed : %#x\n", vlan,
-                       vf, status);
+                       "VLAN %d config on VF %d failed : %#x\n", vlan, vf,
+                       status);
                return be_cmd_status(status);
        }
 
        vf_cfg->vlan_tag = vlan;
-
        return 0;
 }
 
@@ -2772,14 +2823,12 @@ void be_detect_error(struct be_adapter *adapter)
                        }
                }
        } else {
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_LOW, &ue_lo);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_HIGH, &ue_hi);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_LOW_MASK, &ue_lo_mask);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask);
+               ue_lo = ioread32(adapter->pcicfg + PCICFG_UE_STATUS_LOW);
+               ue_hi = ioread32(adapter->pcicfg + PCICFG_UE_STATUS_HIGH);
+               ue_lo_mask = ioread32(adapter->pcicfg +
+                                     PCICFG_UE_STATUS_LOW_MASK);
+               ue_hi_mask = ioread32(adapter->pcicfg +
+                                     PCICFG_UE_STATUS_HI_MASK);
 
                ue_lo = (ue_lo & ~ue_lo_mask);
                ue_hi = (ue_hi & ~ue_hi_mask);
@@ -3339,7 +3388,6 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
                        u32 cap_flags, u32 vf)
 {
        u32 en_flags;
-       int status;
 
        en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                   BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
@@ -3347,10 +3395,7 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
 
        en_flags &= cap_flags;
 
-       status = be_cmd_if_create(adapter, cap_flags, en_flags,
-                                 if_handle, vf);
-
-       return status;
+       return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
 }
 
 static int be_vfs_if_create(struct be_adapter *adapter)
@@ -3368,8 +3413,13 @@ static int be_vfs_if_create(struct be_adapter *adapter)
                if (!BE3_chip(adapter)) {
                        status = be_cmd_get_profile_config(adapter, &res,
                                                           vf + 1);
-                       if (!status)
+                       if (!status) {
                                cap_flags = res.if_cap_flags;
+                               /* Prevent VFs from enabling VLAN promiscuous
+                                * mode
+                                */
+                               cap_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS;
+                       }
                }
 
                status = be_if_create(adapter, &vf_cfg->if_handle,
@@ -3403,7 +3453,6 @@ static int be_vf_setup(struct be_adapter *adapter)
        struct device *dev = &adapter->pdev->dev;
        struct be_vf_cfg *vf_cfg;
        int status, old_vfs, vf;
-       u32 privileges;
 
        old_vfs = pci_num_vf(adapter->pdev);
 
@@ -3433,15 +3482,18 @@ static int be_vf_setup(struct be_adapter *adapter)
 
        for_all_vfs(adapter, vf_cfg, vf) {
                /* Allow VFs to programs MAC/VLAN filters */
-               status = be_cmd_get_fn_privileges(adapter, &privileges, vf + 1);
-               if (!status && !(privileges & BE_PRIV_FILTMGMT)) {
+               status = be_cmd_get_fn_privileges(adapter, &vf_cfg->privileges,
+                                                 vf + 1);
+               if (!status && !(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
                        status = be_cmd_set_fn_privileges(adapter,
-                                                         privileges |
+                                                         vf_cfg->privileges |
                                                          BE_PRIV_FILTMGMT,
                                                          vf + 1);
-                       if (!status)
+                       if (!status) {
+                               vf_cfg->privileges |= BE_PRIV_FILTMGMT;
                                dev_info(dev, "VF%d has FILTMGMT privilege\n",
                                         vf);
+                       }
                }
 
                /* Allow full available bandwidth */
@@ -4820,24 +4872,37 @@ static int be_roce_map_pci_bars(struct be_adapter *adapter)
 
 static int be_map_pci_bars(struct be_adapter *adapter)
 {
+       struct pci_dev *pdev = adapter->pdev;
        u8 __iomem *addr;
 
        if (BEx_chip(adapter) && be_physfn(adapter)) {
-               adapter->csr = pci_iomap(adapter->pdev, 2, 0);
+               adapter->csr = pci_iomap(pdev, 2, 0);
                if (!adapter->csr)
                        return -ENOMEM;
        }
 
-       addr = pci_iomap(adapter->pdev, db_bar(adapter), 0);
+       addr = pci_iomap(pdev, db_bar(adapter), 0);
        if (!addr)
                goto pci_map_err;
        adapter->db = addr;
 
+       if (skyhawk_chip(adapter) || BEx_chip(adapter)) {
+               if (be_physfn(adapter)) {
+                       /* PCICFG is the 2nd BAR in BE2 */
+                       addr = pci_iomap(pdev, BE2_chip(adapter) ? 1 : 0, 0);
+                       if (!addr)
+                               goto pci_map_err;
+                       adapter->pcicfg = addr;
+               } else {
+                       adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
+               }
+       }
+
        be_roce_map_pci_bars(adapter);
        return 0;
 
 pci_map_err:
-       dev_err(&adapter->pdev->dev, "Error in mapping PCI BARs\n");
+       dev_err(&pdev->dev, "Error in mapping PCI BARs\n");
        be_unmap_pci_bars(adapter);
        return -ENOMEM;
 }
index 9bb6220..f6a3a7a 100644 (file)
@@ -1189,13 +1189,12 @@ static void
 fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
 {
        struct  fec_enet_private *fep;
-       struct bufdesc *bdp, *bdp_t;
+       struct bufdesc *bdp;
        unsigned short status;
        struct  sk_buff *skb;
        struct fec_enet_priv_tx_q *txq;
        struct netdev_queue *nq;
        int     index = 0;
-       int     i, bdnum;
        int     entries_free;
 
        fep = netdev_priv(ndev);
@@ -1216,29 +1215,18 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
                if (bdp == txq->cur_tx)
                        break;
 
-               bdp_t = bdp;
-               bdnum = 1;
-               index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep);
-               skb = txq->tx_skbuff[index];
-               while (!skb) {
-                       bdp_t = fec_enet_get_nextdesc(bdp_t, fep, queue_id);
-                       index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep);
-                       skb = txq->tx_skbuff[index];
-                       bdnum++;
-               }
-               if (skb_shinfo(skb)->nr_frags &&
-                   (status = bdp_t->cbd_sc) & BD_ENET_TX_READY)
-                       break;
+               index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 
-               for (i = 0; i < bdnum; i++) {
-                       if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
-                               dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
-                                                bdp->cbd_datlen, DMA_TO_DEVICE);
-                       bdp->cbd_bufaddr = 0;
-                       if (i < bdnum - 1)
-                               bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
-               }
+               skb = txq->tx_skbuff[index];
                txq->tx_skbuff[index] = NULL;
+               if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
+                       dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
+                                       bdp->cbd_datlen, DMA_TO_DEVICE);
+               bdp->cbd_bufaddr = 0;
+               if (!skb) {
+                       bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
+                       continue;
+               }
 
                /* Check for errors. */
                if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
@@ -1479,8 +1467,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 
                        vlan_packet_rcvd = true;
 
-                       skb_copy_to_linear_data_offset(skb, VLAN_HLEN,
-                                                      data, (2 * ETH_ALEN));
+                       memmove(skb->data + VLAN_HLEN, data, ETH_ALEN * 2);
                        skb_pull(skb, VLAN_HLEN);
                }
 
@@ -1597,7 +1584,7 @@ fec_enet_interrupt(int irq, void *dev_id)
        writel(int_events, fep->hwp + FEC_IEVENT);
        fec_enet_collect_events(fep, int_events);
 
-       if (fep->work_tx || fep->work_rx) {
+       if ((fep->work_tx || fep->work_rx) && fep->link) {
                ret = IRQ_HANDLED;
 
                if (napi_schedule_prep(&fep->napi)) {
@@ -1967,6 +1954,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        struct device_node *node;
        int err = -ENXIO, i;
+       u32 mii_speed, holdtime;
 
        /*
         * The i.MX28 dual fec interfaces are not equal.
@@ -2004,10 +1992,33 @@ static int fec_enet_mii_init(struct platform_device *pdev)
         * Reference Manual has an error on this, and gets fixed on i.MX6Q
         * document.
         */
-       fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
+       mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
        if (fep->quirks & FEC_QUIRK_ENET_MAC)
-               fep->phy_speed--;
-       fep->phy_speed <<= 1;
+               mii_speed--;
+       if (mii_speed > 63) {
+               dev_err(&pdev->dev,
+                       "fec clock (%lu) to fast to get right mii speed\n",
+                       clk_get_rate(fep->clk_ipg));
+               err = -EINVAL;
+               goto err_out;
+       }
+
+       /*
+        * The i.MX28 and i.MX6 types have another filed in the MSCR (aka
+        * MII_SPEED) register that defines the MDIO output hold time. Earlier
+        * versions are RAZ there, so just ignore the difference and write the
+        * register always.
+        * The minimal hold time according to IEE802.3 (clause 22) is 10 ns.
+        * HOLDTIME + 1 is the number of clk cycles the fec is holding the
+        * output.
+        * The HOLDTIME bitfield takes values between 0 and 7 (inclusive).
+        * Given that ceil(clkrate / 5000000) <= 64, the calculation for
+        * holdtime cannot result in a value greater than 3.
+        */
+       holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1;
+
+       fep->phy_speed = mii_speed << 1 | holdtime << 8;
+
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
        fep->mii_bus = mdiobus_alloc();
@@ -3383,7 +3394,6 @@ fec_drv_remove(struct platform_device *pdev)
                regulator_disable(fep->reg_phy);
        if (fep->ptp_clock)
                ptp_clock_unregister(fep->ptp_clock);
-       fec_enet_clk_enable(ndev, false);
        of_node_put(fep->phy_node);
        free_netdev(ndev);
 
index 43df788..7bf3682 100644 (file)
@@ -747,6 +747,18 @@ static int gfar_parse_group(struct device_node *np,
        return 0;
 }
 
+static int gfar_of_group_count(struct device_node *np)
+{
+       struct device_node *child;
+       int num = 0;
+
+       for_each_available_child_of_node(np, child)
+               if (!of_node_cmp(child->name, "queue-group"))
+                       num++;
+
+       return num;
+}
+
 static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 {
        const char *model;
@@ -784,7 +796,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                num_rx_qs = 1;
        } else { /* MQ_MG_MODE */
                /* get the actual number of supported groups */
-               unsigned int num_grps = of_get_available_child_count(np);
+               unsigned int num_grps = gfar_of_group_count(np);
 
                if (num_grps == 0 || num_grps > MAXGROUPS) {
                        dev_err(&ofdev->dev, "Invalid # of int groups(%d)\n",
@@ -851,7 +863,10 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 
        /* Parse and initialize group specific information */
        if (priv->mode == MQ_MG_MODE) {
-               for_each_child_of_node(np, child) {
+               for_each_available_child_of_node(np, child) {
+                       if (of_node_cmp(child->name, "queue-group"))
+                               continue;
+
                        err = gfar_parse_group(child, priv, model);
                        if (err)
                                goto err_grp_init;
@@ -3162,8 +3177,8 @@ static void adjust_link(struct net_device *dev)
        struct phy_device *phydev = priv->phydev;
 
        if (unlikely(phydev->link != priv->oldlink ||
-                    phydev->duplex != priv->oldduplex ||
-                    phydev->speed != priv->oldspeed))
+                    (phydev->link && (phydev->duplex != priv->oldduplex ||
+                                      phydev->speed != priv->oldspeed))))
                gfar_update_link_state(priv);
 }
 
index 357e8b5..56b774d 100644 (file)
@@ -3893,6 +3893,9 @@ static int ucc_geth_probe(struct platform_device* ofdev)
        ugeth->phy_interface = phy_interface;
        ugeth->max_speed = max_speed;
 
+       /* Carrier starts down, phylib will bring it up */
+       netif_carrier_off(dev);
+
        err = register_netdev(dev);
        if (err) {
                if (netif_msg_probe(ugeth))
index e8a1adb..c05e507 100644 (file)
@@ -3262,6 +3262,139 @@ static void ehea_remove_device_sysfs(struct platform_device *dev)
        device_remove_file(&dev->dev, &dev_attr_remove_port);
 }
 
+static int ehea_reboot_notifier(struct notifier_block *nb,
+                               unsigned long action, void *unused)
+{
+       if (action == SYS_RESTART) {
+               pr_info("Reboot: freeing all eHEA resources\n");
+               ibmebus_unregister_driver(&ehea_driver);
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block ehea_reboot_nb = {
+       .notifier_call = ehea_reboot_notifier,
+};
+
+static int ehea_mem_notifier(struct notifier_block *nb,
+                            unsigned long action, void *data)
+{
+       int ret = NOTIFY_BAD;
+       struct memory_notify *arg = data;
+
+       mutex_lock(&dlpar_mem_lock);
+
+       switch (action) {
+       case MEM_CANCEL_OFFLINE:
+               pr_info("memory offlining canceled");
+               /* Fall through: re-add canceled memory block */
+
+       case MEM_ONLINE:
+               pr_info("memory is going online");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
+               if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
+                       goto out_unlock;
+               ehea_rereg_mrs();
+               break;
+
+       case MEM_GOING_OFFLINE:
+               pr_info("memory is going offline");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
+               if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
+                       goto out_unlock;
+               ehea_rereg_mrs();
+               break;
+
+       default:
+               break;
+       }
+
+       ehea_update_firmware_handles();
+       ret = NOTIFY_OK;
+
+out_unlock:
+       mutex_unlock(&dlpar_mem_lock);
+       return ret;
+}
+
+static struct notifier_block ehea_mem_nb = {
+       .notifier_call = ehea_mem_notifier,
+};
+
+static void ehea_crash_handler(void)
+{
+       int i;
+
+       if (ehea_fw_handles.arr)
+               for (i = 0; i < ehea_fw_handles.num_entries; i++)
+                       ehea_h_free_resource(ehea_fw_handles.arr[i].adh,
+                                            ehea_fw_handles.arr[i].fwh,
+                                            FORCE_FREE);
+
+       if (ehea_bcmc_regs.arr)
+               for (i = 0; i < ehea_bcmc_regs.num_entries; i++)
+                       ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh,
+                                             ehea_bcmc_regs.arr[i].port_id,
+                                             ehea_bcmc_regs.arr[i].reg_type,
+                                             ehea_bcmc_regs.arr[i].macaddr,
+                                             0, H_DEREG_BCMC);
+}
+
+static atomic_t ehea_memory_hooks_registered;
+
+/* Register memory hooks on probe of first adapter */
+static int ehea_register_memory_hooks(void)
+{
+       int ret = 0;
+
+       if (atomic_inc_and_test(&ehea_memory_hooks_registered))
+               return 0;
+
+       ret = ehea_create_busmap();
+       if (ret) {
+               pr_info("ehea_create_busmap failed\n");
+               goto out;
+       }
+
+       ret = register_reboot_notifier(&ehea_reboot_nb);
+       if (ret) {
+               pr_info("register_reboot_notifier failed\n");
+               goto out;
+       }
+
+       ret = register_memory_notifier(&ehea_mem_nb);
+       if (ret) {
+               pr_info("register_memory_notifier failed\n");
+               goto out2;
+       }
+
+       ret = crash_shutdown_register(ehea_crash_handler);
+       if (ret) {
+               pr_info("crash_shutdown_register failed\n");
+               goto out3;
+       }
+
+       return 0;
+
+out3:
+       unregister_memory_notifier(&ehea_mem_nb);
+out2:
+       unregister_reboot_notifier(&ehea_reboot_nb);
+out:
+       return ret;
+}
+
+static void ehea_unregister_memory_hooks(void)
+{
+       if (atomic_read(&ehea_memory_hooks_registered))
+               return;
+
+       unregister_reboot_notifier(&ehea_reboot_nb);
+       if (crash_shutdown_unregister(ehea_crash_handler))
+               pr_info("failed unregistering crash handler\n");
+       unregister_memory_notifier(&ehea_mem_nb);
+}
+
 static int ehea_probe_adapter(struct platform_device *dev)
 {
        struct ehea_adapter *adapter;
@@ -3269,6 +3402,10 @@ static int ehea_probe_adapter(struct platform_device *dev)
        int ret;
        int i;
 
+       ret = ehea_register_memory_hooks();
+       if (ret)
+               return ret;
+
        if (!dev || !dev->dev.of_node) {
                pr_err("Invalid ibmebus device probed\n");
                return -EINVAL;
@@ -3392,81 +3529,6 @@ static int ehea_remove(struct platform_device *dev)
        return 0;
 }
 
-static void ehea_crash_handler(void)
-{
-       int i;
-
-       if (ehea_fw_handles.arr)
-               for (i = 0; i < ehea_fw_handles.num_entries; i++)
-                       ehea_h_free_resource(ehea_fw_handles.arr[i].adh,
-                                            ehea_fw_handles.arr[i].fwh,
-                                            FORCE_FREE);
-
-       if (ehea_bcmc_regs.arr)
-               for (i = 0; i < ehea_bcmc_regs.num_entries; i++)
-                       ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh,
-                                             ehea_bcmc_regs.arr[i].port_id,
-                                             ehea_bcmc_regs.arr[i].reg_type,
-                                             ehea_bcmc_regs.arr[i].macaddr,
-                                             0, H_DEREG_BCMC);
-}
-
-static int ehea_mem_notifier(struct notifier_block *nb,
-                             unsigned long action, void *data)
-{
-       int ret = NOTIFY_BAD;
-       struct memory_notify *arg = data;
-
-       mutex_lock(&dlpar_mem_lock);
-
-       switch (action) {
-       case MEM_CANCEL_OFFLINE:
-               pr_info("memory offlining canceled");
-               /* Readd canceled memory block */
-       case MEM_ONLINE:
-               pr_info("memory is going online");
-               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
-               if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
-                       goto out_unlock;
-               ehea_rereg_mrs();
-               break;
-       case MEM_GOING_OFFLINE:
-               pr_info("memory is going offline");
-               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
-               if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
-                       goto out_unlock;
-               ehea_rereg_mrs();
-               break;
-       default:
-               break;
-       }
-
-       ehea_update_firmware_handles();
-       ret = NOTIFY_OK;
-
-out_unlock:
-       mutex_unlock(&dlpar_mem_lock);
-       return ret;
-}
-
-static struct notifier_block ehea_mem_nb = {
-       .notifier_call = ehea_mem_notifier,
-};
-
-static int ehea_reboot_notifier(struct notifier_block *nb,
-                               unsigned long action, void *unused)
-{
-       if (action == SYS_RESTART) {
-               pr_info("Reboot: freeing all eHEA resources\n");
-               ibmebus_unregister_driver(&ehea_driver);
-       }
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block ehea_reboot_nb = {
-       .notifier_call = ehea_reboot_notifier,
-};
-
 static int check_module_parm(void)
 {
        int ret = 0;
@@ -3520,26 +3582,10 @@ static int __init ehea_module_init(void)
        if (ret)
                goto out;
 
-       ret = ehea_create_busmap();
-       if (ret)
-               goto out;
-
-       ret = register_reboot_notifier(&ehea_reboot_nb);
-       if (ret)
-               pr_info("failed registering reboot notifier\n");
-
-       ret = register_memory_notifier(&ehea_mem_nb);
-       if (ret)
-               pr_info("failed registering memory remove notifier\n");
-
-       ret = crash_shutdown_register(ehea_crash_handler);
-       if (ret)
-               pr_info("failed registering crash handler\n");
-
        ret = ibmebus_register_driver(&ehea_driver);
        if (ret) {
                pr_err("failed registering eHEA device driver on ebus\n");
-               goto out2;
+               goto out;
        }
 
        ret = driver_create_file(&ehea_driver.driver,
@@ -3547,32 +3593,22 @@ static int __init ehea_module_init(void)
        if (ret) {
                pr_err("failed to register capabilities attribute, ret=%d\n",
                       ret);
-               goto out3;
+               goto out2;
        }
 
        return ret;
 
-out3:
-       ibmebus_unregister_driver(&ehea_driver);
 out2:
-       unregister_memory_notifier(&ehea_mem_nb);
-       unregister_reboot_notifier(&ehea_reboot_nb);
-       crash_shutdown_unregister(ehea_crash_handler);
+       ibmebus_unregister_driver(&ehea_driver);
 out:
        return ret;
 }
 
 static void __exit ehea_module_exit(void)
 {
-       int ret;
-
        driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
        ibmebus_unregister_driver(&ehea_driver);
-       unregister_reboot_notifier(&ehea_reboot_nb);
-       ret = crash_shutdown_unregister(ehea_crash_handler);
-       if (ret)
-               pr_info("failed unregistering crash handler\n");
-       unregister_memory_notifier(&ehea_mem_nb);
+       ehea_unregister_memory_hooks();
        kfree(ehea_fw_handles.arr);
        kfree(ehea_bcmc_regs.arr);
        ehea_destroy_busmap();
index 21978cc..cd7675a 100644 (file)
@@ -1136,6 +1136,8 @@ restart_poll:
        ibmveth_replenish_task(adapter);
 
        if (frames_processed < budget) {
+               napi_complete(napi);
+
                /* We think we are done - reenable interrupts,
                 * then check once more to make sure we are done.
                 */
@@ -1144,8 +1146,6 @@ restart_poll:
 
                BUG_ON(lpar_rc != H_SUCCESS);
 
-               napi_complete(napi);
-
                if (ibmveth_rxq_pending_buffer(adapter) &&
                    napi_reschedule(napi)) {
                        lpar_rc = h_vio_signal(adapter->vdev->unit_address,
@@ -1327,6 +1327,28 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
        return ret;
 }
 
+static int ibmveth_set_mac_addr(struct net_device *dev, void *p)
+{
+       struct ibmveth_adapter *adapter = netdev_priv(dev);
+       struct sockaddr *addr = p;
+       u64 mac_address;
+       int rc;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       mac_address = ibmveth_encode_mac_addr(addr->sa_data);
+       rc = h_change_logical_lan_mac(adapter->vdev->unit_address, mac_address);
+       if (rc) {
+               netdev_err(adapter->netdev, "h_change_logical_lan_mac failed with rc=%d\n", rc);
+               return rc;
+       }
+
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
+
+       return 0;
+}
+
 static const struct net_device_ops ibmveth_netdev_ops = {
        .ndo_open               = ibmveth_open,
        .ndo_stop               = ibmveth_close,
@@ -1337,7 +1359,7 @@ static const struct net_device_ops ibmveth_netdev_ops = {
        .ndo_fix_features       = ibmveth_fix_features,
        .ndo_set_features       = ibmveth_set_features,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = ibmveth_set_mac_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ibmveth_poll_controller,
 #endif
index 11a9ffe..6aea65d 100644 (file)
@@ -868,8 +868,9 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw)
         * The grst delay value is in 100ms units, and we'll wait a
         * couple counts longer to be sure we don't just miss the end.
         */
-       grst_del = rd32(hw, I40E_GLGEN_RSTCTL) & I40E_GLGEN_RSTCTL_GRSTDEL_MASK
-                       >> I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
+       grst_del = (rd32(hw, I40E_GLGEN_RSTCTL) &
+                   I40E_GLGEN_RSTCTL_GRSTDEL_MASK) >>
+                   I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
        for (cnt = 0; cnt < grst_del + 2; cnt++) {
                reg = rd32(hw, I40E_GLGEN_RSTAT);
                if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
@@ -2846,7 +2847,7 @@ i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
 
        status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
 
-       if (!status)
+       if (!status && filter_index)
                *filter_index = resp->index;
 
        return status;
index 183dcb6..a11c70c 100644 (file)
@@ -40,7 +40,7 @@ static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
        u32 val;
 
        val = rd32(hw, I40E_PRTDCB_GENC);
-       *delay = (u16)(val & I40E_PRTDCB_GENC_PFCLDA_MASK >>
+       *delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >>
                       I40E_PRTDCB_GENC_PFCLDA_SHIFT);
 }
 
index 61236f9..c17ee77 100644 (file)
@@ -989,8 +989,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
        if (!cmd_buf)
                return count;
        bytes_not_copied = copy_from_user(cmd_buf, buffer, count);
-       if (bytes_not_copied < 0)
+       if (bytes_not_copied < 0) {
+               kfree(cmd_buf);
                return bytes_not_copied;
+       }
        if (bytes_not_copied > 0)
                count -= bytes_not_copied;
        cmd_buf[count] = '\0';
index cbe281b..dadda3c 100644 (file)
@@ -1512,7 +1512,12 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
        vsi->tc_config.numtc = numtc;
        vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1;
        /* Number of queues per enabled TC */
-       num_tc_qps = vsi->alloc_queue_pairs/numtc;
+       /* In MFP case we can have a much lower count of MSIx
+        * vectors available and so we need to lower the used
+        * q count.
+        */
+       qcount = min_t(int, vsi->alloc_queue_pairs, pf->num_lan_msix);
+       num_tc_qps = qcount / numtc;
        num_tc_qps = min_t(int, num_tc_qps, I40E_MAX_QUEUES_PER_TC);
 
        /* Setup queue offset/count for all TCs for given VSI */
@@ -2684,8 +2689,15 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi)
        u16 qoffset, qcount;
        int i, n;
 
-       if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED))
-               return;
+       if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
+               /* Reset the TC information */
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       rx_ring = vsi->rx_rings[i];
+                       tx_ring = vsi->tx_rings[i];
+                       rx_ring->dcb_tc = 0;
+                       tx_ring->dcb_tc = 0;
+               }
+       }
 
        for (n = 0; n < I40E_MAX_TRAFFIC_CLASS; n++) {
                if (!(vsi->tc_config.enabled_tc & (1 << n)))
@@ -3830,6 +3842,12 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
 {
        int i;
 
+       i40e_stop_misc_vector(pf);
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               synchronize_irq(pf->msix_entries[0].vector);
+               free_irq(pf->msix_entries[0].vector, pf);
+       }
+
        i40e_put_lump(pf->irq_pile, 0, I40E_PILE_VALID_BIT-1);
        for (i = 0; i < pf->num_alloc_vsi; i++)
                if (pf->vsi[i])
@@ -5254,8 +5272,14 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
 
        /* Wait for the PF's Tx queues to be disabled */
        ret = i40e_pf_wait_txq_disabled(pf);
-       if (!ret)
+       if (ret) {
+               /* Schedule PF reset to recover */
+               set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
+               i40e_service_event_schedule(pf);
+       } else {
                i40e_pf_unquiesce_all_vsi(pf);
+       }
+
 exit:
        return ret;
 }
@@ -5587,7 +5611,8 @@ static void i40e_check_hang_subtask(struct i40e_pf *pf)
        int i, v;
 
        /* If we're down or resetting, just bail */
-       if (test_bit(__I40E_CONFIG_BUSY, &pf->state))
+       if (test_bit(__I40E_DOWN, &pf->state) ||
+           test_bit(__I40E_CONFIG_BUSY, &pf->state))
                return;
 
        /* for each VSI/netdev
@@ -9533,6 +9558,7 @@ static void i40e_remove(struct pci_dev *pdev)
        set_bit(__I40E_DOWN, &pf->state);
        del_timer_sync(&pf->service_timer);
        cancel_work_sync(&pf->service_task);
+       i40e_fdir_teardown(pf);
 
        if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
                i40e_free_vfs(pf);
@@ -9559,12 +9585,6 @@ static void i40e_remove(struct pci_dev *pdev)
        if (pf->vsi[pf->lan_vsi])
                i40e_vsi_release(pf->vsi[pf->lan_vsi]);
 
-       i40e_stop_misc_vector(pf);
-       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
-               synchronize_irq(pf->msix_entries[0].vector);
-               free_irq(pf->msix_entries[0].vector, pf);
-       }
-
        /* shutdown and destroy the HMC */
        if (pf->hw.hmc.hmc_obj) {
                ret_code = i40e_shutdown_lan_hmc(&pf->hw);
@@ -9718,6 +9738,8 @@ static void i40e_shutdown(struct pci_dev *pdev)
        wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
        wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
 
+       i40e_clear_interrupt_scheme(pf);
+
        if (system_state == SYSTEM_POWER_OFF) {
                pci_wake_from_d3(pdev, pf->wol_en);
                pci_set_power_state(pdev, PCI_D3hot);
index 3e70f2e..5defe0d 100644 (file)
@@ -679,9 +679,11 @@ static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
 {
        i40e_status status;
        enum i40e_nvmupd_cmd upd_cmd;
+       bool retry_attempt = false;
 
        upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
 
+retry:
        switch (upd_cmd) {
        case I40E_NVMUPD_WRITE_CON:
                status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
@@ -725,6 +727,39 @@ static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
                *errno = -ESRCH;
                break;
        }
+
+       /* In some circumstances, a multi-write transaction takes longer
+        * than the default 3 minute timeout on the write semaphore.  If
+        * the write failed with an EBUSY status, this is likely the problem,
+        * so here we try to reacquire the semaphore then retry the write.
+        * We only do one retry, then give up.
+        */
+       if (status && (hw->aq.asq_last_status == I40E_AQ_RC_EBUSY) &&
+           !retry_attempt) {
+               i40e_status old_status = status;
+               u32 old_asq_status = hw->aq.asq_last_status;
+               u32 gtime;
+
+               gtime = rd32(hw, I40E_GLVFGEN_TIMER);
+               if (gtime >= hw->nvm.hw_semaphore_timeout) {
+                       i40e_debug(hw, I40E_DEBUG_ALL,
+                                  "NVMUPD: write semaphore expired (%d >= %lld), retrying\n",
+                                  gtime, hw->nvm.hw_semaphore_timeout);
+                       i40e_release_nvm(hw);
+                       status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
+                       if (status) {
+                               i40e_debug(hw, I40E_DEBUG_ALL,
+                                          "NVMUPD: write semaphore reacquire failed aq_err = %d\n",
+                                          hw->aq.asq_last_status);
+                               status = old_status;
+                               hw->aq.asq_last_status = old_asq_status;
+                       } else {
+                               retry_attempt = true;
+                               goto retry;
+                       }
+               }
+       }
+
        return status;
 }
 
index 2206d2d..bbf1b12 100644 (file)
@@ -585,6 +585,20 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
        }
 }
 
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring:  tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+       return le32_to_cpu(*(volatile __le32 *)head);
+}
+
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
  * @tx_ring: the ring of descriptors
@@ -594,10 +608,16 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
  **/
 static u32 i40e_get_tx_pending(struct i40e_ring *ring)
 {
-       u32 ntu = ((ring->next_to_clean <= ring->next_to_use)
-                       ? ring->next_to_use
-                       : ring->next_to_use + ring->count);
-       return ntu - ring->next_to_clean;
+       u32 head, tail;
+
+       head = i40e_get_head(ring);
+       tail = readl(ring->tail);
+
+       if (head != tail)
+               return (head < tail) ?
+                       tail - head : (tail + ring->count - head);
+
+       return 0;
 }
 
 /**
@@ -606,6 +626,8 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
  **/
 static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
 {
+       u32 tx_done = tx_ring->stats.packets;
+       u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
        u32 tx_pending = i40e_get_tx_pending(tx_ring);
        struct i40e_pf *pf = tx_ring->vsi->back;
        bool ret = false;
@@ -623,41 +645,25 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * run the check_tx_hang logic with a transmit completion
         * pending but without time to complete it yet.
         */
-       if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           (tx_pending >= I40E_MIN_DESC_PENDING)) {
+       if ((tx_done_old == tx_done) && tx_pending) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
-       } else if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-                  (tx_pending < I40E_MIN_DESC_PENDING) &&
-                  (tx_pending > 0)) {
+       } else if (tx_done_old == tx_done &&
+                  (tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
                if (I40E_DEBUG_FLOW & pf->hw.debug_mask)
                        dev_info(tx_ring->dev, "HW needs some more descs to do a cacheline flush. tx_pending %d, queue %d",
                                 tx_pending, tx_ring->queue_index);
                pf->tx_sluggish_count++;
        } else {
                /* update completed stats and disarm the hang check */
-               tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
+               tx_ring->tx_stats.tx_done_old = tx_done;
                clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
        }
 
        return ret;
 }
 
-/**
- * i40e_get_head - Retrieve head from head writeback
- * @tx_ring:  tx ring to fetch head of
- *
- * Returns value of Tx ring head based on value stored
- * in head write-back location
- **/
-static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
-{
-       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
-
-       return le32_to_cpu(*(volatile __le32 *)head);
-}
-
 #define WB_STRIDE 0x3
 
 /**
@@ -2139,6 +2145,67 @@ static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
        return __i40e_maybe_stop_tx(tx_ring, size);
 }
 
+/**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @tx_flags: collected send information
+ * @hdr_len:  size of the packet header
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
+                              const u8 hdr_len)
+{
+       struct skb_frag_struct *frag;
+       bool linearize = false;
+       unsigned int size = 0;
+       u16 num_frags;
+       u16 gso_segs;
+
+       num_frags = skb_shinfo(skb)->nr_frags;
+       gso_segs = skb_shinfo(skb)->gso_segs;
+
+       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
+               u16 j = 1;
+
+               if (num_frags < (I40E_MAX_BUFFER_TXD))
+                       goto linearize_chk_done;
+               /* try the simple math, if we have too many frags per segment */
+               if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
+                   I40E_MAX_BUFFER_TXD) {
+                       linearize = true;
+                       goto linearize_chk_done;
+               }
+               frag = &skb_shinfo(skb)->frags[0];
+               size = hdr_len;
+               /* we might still have more fragments per segment */
+               do {
+                       size += skb_frag_size(frag);
+                       frag++; j++;
+                       if (j == I40E_MAX_BUFFER_TXD) {
+                               if (size < skb_shinfo(skb)->gso_size) {
+                                       linearize = true;
+                                       break;
+                               }
+                               j = 1;
+                               size -= skb_shinfo(skb)->gso_size;
+                               if (size)
+                                       j++;
+                               size += hdr_len;
+                       }
+                       num_frags--;
+               } while (num_frags);
+       } else {
+               if (num_frags >= I40E_MAX_BUFFER_TXD)
+                       linearize = true;
+       }
+
+linearize_chk_done:
+       return linearize;
+}
+
 /**
  * i40e_tx_map - Build the Tx descriptor
  * @tx_ring:  ring to send buffer on
@@ -2396,6 +2463,10 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        if (tsyn)
                tx_flags |= I40E_TX_FLAGS_TSYN;
 
+       if (i40e_chk_linearize(skb, tx_flags, hdr_len))
+               if (skb_linearize(skb))
+                       goto out_drop;
+
        skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
index 18b0023..dff0bae 100644 (file)
@@ -112,6 +112,7 @@ enum i40e_dyn_idx_t {
 
 #define i40e_rx_desc i40e_32byte_rx_desc
 
+#define I40E_MAX_BUFFER_TXD    8
 #define I40E_MIN_TX_LEN                17
 #define I40E_MAX_DATA_PER_TXD  8192
 
index 2900438..7088915 100644 (file)
@@ -125,6 +125,20 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
        }
 }
 
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring:  tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+       return le32_to_cpu(*(volatile __le32 *)head);
+}
+
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
  * @tx_ring: the ring of descriptors
@@ -134,10 +148,16 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
  **/
 static u32 i40e_get_tx_pending(struct i40e_ring *ring)
 {
-       u32 ntu = ((ring->next_to_clean <= ring->next_to_use)
-                       ? ring->next_to_use
-                       : ring->next_to_use + ring->count);
-       return ntu - ring->next_to_clean;
+       u32 head, tail;
+
+       head = i40e_get_head(ring);
+       tail = readl(ring->tail);
+
+       if (head != tail)
+               return (head < tail) ?
+                       tail - head : (tail + ring->count - head);
+
+       return 0;
 }
 
 /**
@@ -146,6 +166,8 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
  **/
 static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
 {
+       u32 tx_done = tx_ring->stats.packets;
+       u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
        u32 tx_pending = i40e_get_tx_pending(tx_ring);
        bool ret = false;
 
@@ -162,36 +184,20 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * run the check_tx_hang logic with a transmit completion
         * pending but without time to complete it yet.
         */
-       if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           (tx_pending >= I40E_MIN_DESC_PENDING)) {
+       if ((tx_done_old == tx_done) && tx_pending) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
-       } else if (!(tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) ||
-                  !(tx_pending < I40E_MIN_DESC_PENDING) ||
-                  !(tx_pending > 0)) {
+       } else if (tx_done_old == tx_done &&
+                  (tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
                /* update completed stats and disarm the hang check */
-               tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
+               tx_ring->tx_stats.tx_done_old = tx_done;
                clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
        }
 
        return ret;
 }
 
-/**
- * i40e_get_head - Retrieve head from head writeback
- * @tx_ring:  tx ring to fetch head of
- *
- * Returns value of Tx ring head based on value stored
- * in head write-back location
- **/
-static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
-{
-       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
-
-       return le32_to_cpu(*(volatile __le32 *)head);
-}
-
 #define WB_STRIDE 0x3
 
 /**
@@ -1206,17 +1212,16 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       if (protocol == htons(ETH_P_IP)) {
-               iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+       iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+       ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+
+       if (iph->version == 4) {
                tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
                tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
                                                 0, IPPROTO_TCP, 0);
-       } else if (skb_is_gso_v6(skb)) {
-
-               ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb)
-                                          : ipv6_hdr(skb);
+       } else if (ipv6h->version == 6) {
                tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                ipv6h->payload_len = 0;
                tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
@@ -1274,13 +1279,9 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
                                         I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
                        }
                } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
-                       if (tx_flags & I40E_TX_FLAGS_TSO) {
-                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       if (tx_flags & I40E_TX_FLAGS_TSO)
                                ip_hdr(skb)->check = 0;
-                       } else {
-                               *cd_tunneling |=
-                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-                       }
                }
 
                /* Now set the ctx descriptor fields */
@@ -1290,6 +1291,11 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
                                   ((skb_inner_network_offset(skb) -
                                        skb_transport_offset(skb)) >> 1) <<
                                   I40E_TXD_CTX_QW0_NATLEN_SHIFT;
+               if (this_ip_hdr->version == 6) {
+                       tx_flags &= ~I40E_TX_FLAGS_IPV4;
+                       tx_flags |= I40E_TX_FLAGS_IPV6;
+               }
+
 
        } else {
                network_hdr_len = skb_network_header_len(skb);
@@ -1380,6 +1386,67 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
        context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss);
 }
 
+ /**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @tx_flags: collected send information
+ * @hdr_len:  size of the packet header
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
+                              const u8 hdr_len)
+{
+       struct skb_frag_struct *frag;
+       bool linearize = false;
+       unsigned int size = 0;
+       u16 num_frags;
+       u16 gso_segs;
+
+       num_frags = skb_shinfo(skb)->nr_frags;
+       gso_segs = skb_shinfo(skb)->gso_segs;
+
+       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
+               u16 j = 1;
+
+               if (num_frags < (I40E_MAX_BUFFER_TXD))
+                       goto linearize_chk_done;
+               /* try the simple math, if we have too many frags per segment */
+               if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
+                   I40E_MAX_BUFFER_TXD) {
+                       linearize = true;
+                       goto linearize_chk_done;
+               }
+               frag = &skb_shinfo(skb)->frags[0];
+               size = hdr_len;
+               /* we might still have more fragments per segment */
+               do {
+                       size += skb_frag_size(frag);
+                       frag++; j++;
+                       if (j == I40E_MAX_BUFFER_TXD) {
+                               if (size < skb_shinfo(skb)->gso_size) {
+                                       linearize = true;
+                                       break;
+                               }
+                               j = 1;
+                               size -= skb_shinfo(skb)->gso_size;
+                               if (size)
+                                       j++;
+                               size += hdr_len;
+                       }
+                       num_frags--;
+               } while (num_frags);
+       } else {
+               if (num_frags >= I40E_MAX_BUFFER_TXD)
+                       linearize = true;
+       }
+
+linearize_chk_done:
+       return linearize;
+}
+
 /**
  * i40e_tx_map - Build the Tx descriptor
  * @tx_ring:  ring to send buffer on
@@ -1654,6 +1721,10 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        else if (tso)
                tx_flags |= I40E_TX_FLAGS_TSO;
 
+       if (i40e_chk_linearize(skb, tx_flags, hdr_len))
+               if (skb_linearize(skb))
+                       goto out_drop;
+
        skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
index 4e15903..c950a03 100644 (file)
@@ -112,6 +112,7 @@ enum i40e_dyn_idx_t {
 
 #define i40e_rx_desc i40e_32byte_rx_desc
 
+#define I40E_MAX_BUFFER_TXD    8
 #define I40E_MIN_TX_LEN                17
 #define I40E_MAX_DATA_PER_TXD  8192
 
index 96208f1..2db6532 100644 (file)
@@ -2658,16 +2658,11 @@ static int mvneta_stop(struct net_device *dev)
 static int mvneta_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct mvneta_port *pp = netdev_priv(dev);
-       int ret;
 
        if (!pp->phy_dev)
                return -ENOTSUPP;
 
-       ret = phy_mii_ioctl(pp->phy_dev, ifr, cmd);
-       if (!ret)
-               mvneta_adjust_link(dev);
-
-       return ret;
+       return phy_mii_ioctl(pp->phy_dev, ifr, cmd);
 }
 
 /* Ethtool methods */
index a681d7c..546ca42 100644 (file)
@@ -724,7 +724,8 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
                 * on the host, we deprecate the error message for this
                 * specific command/input_mod/opcode_mod/fw-status to be debug.
                 */
-               if (op == MLX4_CMD_SET_PORT && in_modifier == 1 &&
+               if (op == MLX4_CMD_SET_PORT &&
+                   (in_modifier == 1 || in_modifier == 2) &&
                    op_modifier == 0 && context->fw_status == CMD_STAT_BAD_SIZE)
                        mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n",
                                 op, context->fw_status);
@@ -1993,7 +1994,6 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
                        goto reset_slave;
                slave_state[slave].vhcr_dma = ((u64) param) << 48;
                priv->mfunc.master.slave_state[slave].cookie = 0;
-               mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]);
                break;
        case MLX4_COMM_CMD_VHCR1:
                if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0)
@@ -2225,6 +2225,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
                for (i = 0; i < dev->num_slaves; ++i) {
                        s_state = &priv->mfunc.master.slave_state[i];
                        s_state->last_cmd = MLX4_COMM_CMD_RESET;
+                       mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]);
                        for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j)
                                s_state->event_eq[j].eqn = -1;
                        __raw_writel((__force u32) 0,
index 2a210c4..3485acf 100644 (file)
@@ -1698,8 +1698,6 @@ int mlx4_en_start_port(struct net_device *dev)
        /* Schedule multicast task to populate multicast list */
        queue_work(mdev->workqueue, &priv->rx_mode_task);
 
-       mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
-
 #ifdef CONFIG_MLX4_EN_VXLAN
        if (priv->mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
                vxlan_get_rx_port(dev);
@@ -2807,13 +2805,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        netif_carrier_off(dev);
        mlx4_en_set_default_moderation(priv);
 
-       err = register_netdev(dev);
-       if (err) {
-               en_err(priv, "Netdev registration failed for port %d\n", port);
-               goto out;
-       }
-       priv->registered = 1;
-
        en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
        en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
 
@@ -2853,6 +2844,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                queue_delayed_work(mdev->workqueue, &priv->service_task,
                                   SERVICE_TASK_DELAY);
 
+       mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
+
+       err = register_netdev(dev);
+       if (err) {
+               en_err(priv, "Netdev registration failed for port %d\n", port);
+               goto out;
+       }
+
+       priv->registered = 1;
+
        return 0;
 
 out:
index 2d8ee66..a61009f 100644 (file)
@@ -81,12 +81,14 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
 {
        u32 loopback_ok = 0;
        int i;
-
+       bool gro_enabled;
 
         priv->loopback_ok = 0;
        priv->validate_loopback = 1;
+       gro_enabled = priv->dev->features & NETIF_F_GRO;
 
        mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+       priv->dev->features &= ~NETIF_F_GRO;
 
        /* xmit */
        if (mlx4_en_test_loopback_xmit(priv)) {
@@ -108,6 +110,10 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
 mlx4_en_test_loopback_exit:
 
        priv->validate_loopback = 0;
+
+       if (gro_enabled)
+               priv->dev->features |= NETIF_F_GRO;
+
        mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
        return !loopback_ok;
 }
index 264bc15..6e70ffe 100644 (file)
@@ -153,12 +153,10 @@ void mlx4_gen_slave_eqe(struct work_struct *work)
 
                /* All active slaves need to receive the event */
                if (slave == ALL_SLAVES) {
-                       for (i = 0; i < dev->num_slaves; i++) {
-                               if (i != dev->caps.function &&
-                                   master->slave_state[i].active)
-                                       if (mlx4_GEN_EQE(dev, i, eqe))
-                                               mlx4_warn(dev, "Failed to generate event for slave %d\n",
-                                                         i);
+                       for (i = 0; i <= dev->persist->num_vfs; i++) {
+                               if (mlx4_GEN_EQE(dev, i, eqe))
+                                       mlx4_warn(dev, "Failed to generate event for slave %d\n",
+                                                 i);
                        }
                } else {
                        if (mlx4_GEN_EQE(dev, slave, eqe))
@@ -203,13 +201,11 @@ static void mlx4_slave_event(struct mlx4_dev *dev, int slave,
                             struct mlx4_eqe *eqe)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       struct mlx4_slave_state *s_slave =
-               &priv->mfunc.master.slave_state[slave];
 
-       if (!s_slave->active) {
-               /*mlx4_warn(dev, "Trying to pass event to inactive slave\n");*/
+       if (slave < 0 || slave > dev->persist->num_vfs ||
+           slave == dev->caps.function ||
+           !priv->mfunc.master.slave_state[slave].active)
                return;
-       }
 
        slave_event(dev, slave, eqe);
 }
index 2a8268e..ebbe244 100644 (file)
@@ -453,7 +453,7 @@ struct mlx4_en_port_stats {
        unsigned long rx_chksum_none;
        unsigned long rx_chksum_complete;
        unsigned long tx_chksum_offload;
-#define NUM_PORT_STATS         9
+#define NUM_PORT_STATS         10
 };
 
 struct mlx4_en_perf_stats {
index 2bb8553..eda29db 100644 (file)
@@ -412,7 +412,6 @@ err_icm:
 
 EXPORT_SYMBOL_GPL(mlx4_qp_alloc);
 
-#define MLX4_UPDATE_QP_SUPPORTED_ATTRS MLX4_UPDATE_QP_SMAC
 int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
                   enum mlx4_update_qp_attr attr,
                   struct mlx4_update_qp_params *params)
index 486e3d2..6e413ac 100644 (file)
@@ -713,7 +713,7 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
        struct mlx4_vport_oper_state *vp_oper;
        struct mlx4_priv *priv;
        u32 qp_type;
-       int port;
+       int port, err = 0;
 
        port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
        priv = mlx4_priv(dev);
@@ -738,7 +738,9 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
                        } else {
                                struct mlx4_update_qp_params params = {.flags = 0};
 
-                               mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, &params);
+                               err = mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, &params);
+                               if (err)
+                                       goto out;
                        }
                }
 
@@ -773,7 +775,8 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
                qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC;
                qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;
        }
-       return 0;
+out:
+       return err;
 }
 
 static int mpt_mask(struct mlx4_dev *dev)
@@ -3092,6 +3095,12 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)
        if (!priv->mfunc.master.slave_state)
                return -EINVAL;
 
+       /* check for slave valid, slave not PF, and slave active */
+       if (slave < 0 || slave > dev->persist->num_vfs ||
+           slave == dev->caps.function ||
+           !priv->mfunc.master.slave_state[slave].active)
+               return 0;
+
        event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type];
 
        /* Create the event only if the slave is registered */
index 44e8d7d..57a6e6c 100644 (file)
@@ -1239,11 +1239,9 @@ static int pasemi_mac_open(struct net_device *dev)
        if (mac->phydev)
                phy_start(mac->phydev);
 
-       init_timer(&mac->tx->clean_timer);
-       mac->tx->clean_timer.function = pasemi_mac_tx_timer;
-       mac->tx->clean_timer.data = (unsigned long)mac->tx;
-       mac->tx->clean_timer.expires = jiffies+HZ;
-       add_timer(&mac->tx->clean_timer);
+       setup_timer(&mac->tx->clean_timer, pasemi_mac_tx_timer,
+                   (unsigned long)mac->tx);
+       mod_timer(&mac->tx->clean_timer, jiffies + HZ);
 
        return 0;
 
index 6e426ae..0a5e204 100644 (file)
@@ -354,7 +354,7 @@ struct cmd_desc_type0 {
 
 } __attribute__ ((aligned(64)));
 
-/* Note: sizeof(rcv_desc) should always be a mutliple of 2 */
+/* Note: sizeof(rcv_desc) should always be a multiple of 2 */
 struct rcv_desc {
        __le16 reference_handle;
        __le16 reserved;
@@ -499,7 +499,7 @@ struct uni_data_desc{
 #define NETXEN_IMAGE_START     0x43000 /* compressed image */
 #define NETXEN_SECONDARY_START 0x200000        /* backup images */
 #define NETXEN_PXE_START       0x3E0000        /* PXE boot rom */
-#define NETXEN_USER_START      0x3E8000        /* Firmare info */
+#define NETXEN_USER_START      0x3E8000        /* Firmware info */
 #define NETXEN_FIXED_START     0x3F0000        /* backup of crbinit */
 #define NETXEN_USER_START_OLD  NETXEN_PXE_START /* very old flash */
 
index fa43176..f221126 100644 (file)
@@ -314,7 +314,7 @@ struct qlcnic_fdt {
 #define QLCNIC_BRDCFG_START    0x4000          /* board config */
 #define QLCNIC_BOOTLD_START    0x10000         /* bootld */
 #define QLCNIC_IMAGE_START     0x43000         /* compressed image */
-#define QLCNIC_USER_START      0x3E8000        /* Firmare info */
+#define QLCNIC_USER_START      0x3E8000        /* Firmware info */
 
 #define QLCNIC_FW_VERSION_OFFSET       (QLCNIC_USER_START+0x408)
 #define QLCNIC_FW_SIZE_OFFSET          (QLCNIC_USER_START+0x40c)
index ad0020a..c70ab40 100644 (file)
@@ -2561,7 +2561,7 @@ static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
        int rc = -EINVAL;
 
        if (!rtl_fw_format_ok(tp, rtl_fw)) {
-               netif_err(tp, ifup, dev, "invalid firwmare\n");
+               netif_err(tp, ifup, dev, "invalid firmware\n");
                goto out;
        }
 
@@ -5067,8 +5067,6 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
        RTL_W8(ChipCmd, CmdReset);
 
        rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
-
-       netdev_reset_queue(tp->dev);
 }
 
 static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
@@ -7049,7 +7047,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
        u32 status, len;
        u32 opts[2];
        int frags;
-       bool stop_queue;
 
        if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
                netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
@@ -7090,8 +7087,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 
        txd->opts2 = cpu_to_le32(opts[1]);
 
-       netdev_sent_queue(dev, skb->len);
-
        skb_tx_timestamp(skb);
 
        /* Force memory writes to complete before releasing descriptor */
@@ -7106,16 +7101,11 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 
        tp->cur_tx += frags + 1;
 
-       stop_queue = !TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS);
+       RTL_W8(TxPoll, NPQ);
 
-       if (!skb->xmit_more || stop_queue ||
-           netif_xmit_stopped(netdev_get_tx_queue(dev, 0))) {
-               RTL_W8(TxPoll, NPQ);
-
-               mmiowb();
-       }
+       mmiowb();
 
-       if (stop_queue) {
+       if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
                /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
                 * not miss a ring update when it notices a stopped queue.
                 */
@@ -7198,7 +7188,6 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
 static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
 {
        unsigned int dirty_tx, tx_left;
-       unsigned int bytes_compl = 0, pkts_compl = 0;
 
        dirty_tx = tp->dirty_tx;
        smp_rmb();
@@ -7222,8 +7211,10 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
                rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
                                     tp->TxDescArray + entry);
                if (status & LastFrag) {
-                       pkts_compl++;
-                       bytes_compl += tx_skb->skb->len;
+                       u64_stats_update_begin(&tp->tx_stats.syncp);
+                       tp->tx_stats.packets++;
+                       tp->tx_stats.bytes += tx_skb->skb->len;
+                       u64_stats_update_end(&tp->tx_stats.syncp);
                        dev_kfree_skb_any(tx_skb->skb);
                        tx_skb->skb = NULL;
                }
@@ -7232,13 +7223,6 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
        }
 
        if (tp->dirty_tx != dirty_tx) {
-               netdev_completed_queue(tp->dev, pkts_compl, bytes_compl);
-
-               u64_stats_update_begin(&tp->tx_stats.syncp);
-               tp->tx_stats.packets += pkts_compl;
-               tp->tx_stats.bytes += bytes_compl;
-               u64_stats_update_end(&tp->tx_stats.syncp);
-
                tp->dirty_tx = dirty_tx;
                /* Sync with rtl8169_start_xmit:
                 * - publish dirty_tx ring index (write barrier)
index 4da8bd2..736d5d1 100644 (file)
@@ -508,7 +508,6 @@ static struct sh_eth_cpu_data r8a779x_data = {
        .tpauser        = 1,
        .hw_swap        = 1,
        .rmiimode       = 1,
-       .shift_rd0      = 1,
 };
 
 static void sh_eth_set_rate_sh7724(struct net_device *ndev)
@@ -1392,6 +1391,9 @@ static void sh_eth_dev_exit(struct net_device *ndev)
        msleep(2); /* max frame time at 10 Mbps < 1250 us */
        sh_eth_get_stats(ndev);
        sh_eth_reset(ndev);
+
+       /* Set MAC address again */
+       update_mac_address(ndev);
 }
 
 /* free Tx skb function */
@@ -1407,6 +1409,8 @@ static int sh_eth_txfree(struct net_device *ndev)
                txdesc = &mdp->tx_ring[entry];
                if (txdesc->status & cpu_to_edmac(mdp, TD_TACT))
                        break;
+               /* TACT bit must be checked before all the following reads */
+               rmb();
                /* Free the original skb. */
                if (mdp->tx_skbuff[entry]) {
                        dma_unmap_single(&ndev->dev, txdesc->addr,
@@ -1444,6 +1448,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        limit = boguscnt;
        rxdesc = &mdp->rx_ring[entry];
        while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) {
+               /* RACT bit must be checked before all the following reads */
+               rmb();
                desc_status = edmac_to_cpu(mdp, rxdesc->status);
                pkt_len = rxdesc->frame_length;
 
@@ -1455,8 +1461,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
 
                /* In case of almost all GETHER/ETHERs, the Receive Frame State
                 * (RFS) bits in the Receive Descriptor 0 are from bit 9 to
-                * bit 0. However, in case of the R8A7740, R8A779x, and
-                * R7S72100 the RFS bits are from bit 25 to bit 16. So, the
+                * bit 0. However, in case of the R8A7740 and R7S72100
+                * the RFS bits are from bit 25 to bit 16. So, the
                 * driver needs right shifting by 16.
                 */
                if (mdp->cd->shift_rd0)
@@ -1523,6 +1529,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                        skb_checksum_none_assert(skb);
                        rxdesc->addr = dma_addr;
                }
+               wmb(); /* RACT bit must be set after all the above writes */
                if (entry >= mdp->num_rx_ring - 1)
                        rxdesc->status |=
                                cpu_to_edmac(mdp, RD_RACT | RD_RFP | RD_RDEL);
@@ -1535,7 +1542,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        /* If we don't need to check status, don't. -KDU */
        if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) {
                /* fix the values for the next receiving if RDE is set */
-               if (intr_status & EESR_RDE) {
+               if (intr_status & EESR_RDE && mdp->reg_offset[RDFAR] != 0) {
                        u32 count = (sh_eth_read(ndev, RDFAR) -
                                     sh_eth_read(ndev, RDLAR)) >> 4;
 
@@ -2174,7 +2181,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        spin_unlock_irqrestore(&mdp->lock, flags);
 
-       if (skb_padto(skb, ETH_ZLEN))
+       if (skb_put_padto(skb, ETH_ZLEN))
                return NETDEV_TX_OK;
 
        entry = mdp->cur_tx % mdp->num_tx_ring;
@@ -2192,6 +2199,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        txdesc->buffer_length = skb->len;
 
+       wmb(); /* TACT bit must be set after all the above writes */
        if (entry >= mdp->num_tx_ring - 1)
                txdesc->status |= cpu_to_edmac(mdp, TD_TACT | TD_TDLE);
        else
index 34389b6..5cecec2 100644 (file)
@@ -1257,9 +1257,9 @@ static void rocker_port_set_enable(struct rocker_port *rocker_port, bool enable)
        u64 val = rocker_read64(rocker_port->rocker, PORT_PHYS_ENABLE);
 
        if (enable)
-               val |= 1 << rocker_port->lport;
+               val |= 1ULL << rocker_port->lport;
        else
-               val &= ~(1 << rocker_port->lport);
+               val &= ~(1ULL << rocker_port->lport);
        rocker_write64(rocker_port->rocker, PORT_PHYS_ENABLE, val);
 }
 
@@ -4201,6 +4201,8 @@ static int rocker_probe_ports(struct rocker *rocker)
 
        alloc_size = sizeof(struct rocker_port *) * rocker->port_count;
        rocker->ports = kmalloc(alloc_size, GFP_KERNEL);
+       if (!rocker->ports)
+               return -ENOMEM;
        for (i = 0; i < rocker->port_count; i++) {
                err = rocker_probe_port(rocker, i);
                if (err)
@@ -4466,10 +4468,16 @@ static int rocker_port_master_changed(struct net_device *dev)
        struct net_device *master = netdev_master_upper_dev_get(dev);
        int err = 0;
 
+       /* There are currently three cases handled here:
+        * 1. Joining a bridge
+        * 2. Leaving a previously joined bridge
+        * 3. Other, e.g. being added to or removed from a bond or openvswitch,
+        *    in which case nothing is done
+        */
        if (master && master->rtnl_link_ops &&
            !strcmp(master->rtnl_link_ops->kind, "bridge"))
                err = rocker_port_bridge_join(rocker_port, master);
-       else
+       else if (rocker_port_is_bridged(rocker_port))
                err = rocker_port_bridge_leave(rocker_port);
 
        return err;
index 6b33127..3449893 100644 (file)
@@ -1070,11 +1070,8 @@ static int smc_open(struct net_device *dev)
     smc->packets_waiting = 0;
 
     smc_reset(dev);
-    init_timer(&smc->media);
-    smc->media.function = media_check;
-    smc->media.data = (u_long) dev;
-    smc->media.expires = jiffies + HZ;
-    add_timer(&smc->media);
+    setup_timer(&smc->media, media_check, (u_long)dev);
+    mod_timer(&smc->media, jiffies + HZ);
 
     return 0;
 } /* smc_open */
index 88a55f9..8678e39 100644 (file)
@@ -91,6 +91,11 @@ static const char version[] =
 
 #include "smc91x.h"
 
+#if defined(CONFIG_ASSABET_NEPONSET)
+#include <mach/assabet.h>
+#include <mach/neponset.h>
+#endif
+
 #ifndef SMC_NOWAIT
 # define SMC_NOWAIT            0
 #endif
@@ -2243,10 +2248,9 @@ static int smc_drv_probe(struct platform_device *pdev)
        const struct of_device_id *match = NULL;
        struct smc_local *lp;
        struct net_device *ndev;
-       struct resource *res;
+       struct resource *res, *ires;
        unsigned int __iomem *addr;
        unsigned long irq_flags = SMC_IRQ_FLAGS;
-       unsigned long irq_resflags;
        int ret;
 
        ndev = alloc_etherdev(sizeof(struct smc_local));
@@ -2338,25 +2342,23 @@ static int smc_drv_probe(struct platform_device *pdev)
                goto out_free_netdev;
        }
 
-       ndev->irq = platform_get_irq(pdev, 0);
-       if (ndev->irq <= 0) {
+       ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!ires) {
                ret = -ENODEV;
                goto out_release_io;
        }
-       /*
-        * If this platform does not specify any special irqflags, or if
-        * the resource supplies a trigger, override the irqflags with
-        * the trigger flags from the resource.
-        */
-       irq_resflags = irqd_get_trigger_type(irq_get_irq_data(ndev->irq));
-       if (irq_flags == -1 || irq_resflags & IRQF_TRIGGER_MASK)
-               irq_flags = irq_resflags & IRQF_TRIGGER_MASK;
+
+       ndev->irq = ires->start;
+
+       if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK)
+               irq_flags = ires->flags & IRQF_TRIGGER_MASK;
 
        ret = smc_request_attrib(pdev, ndev);
        if (ret)
                goto out_release_io;
-#if defined(CONFIG_SA1100_ASSABET)
-       neponset_ncr_set(NCR_ENET_OSC_EN);
+#if defined(CONFIG_ASSABET_NEPONSET)
+       if (machine_is_assabet() && machine_has_neponset())
+               neponset_ncr_set(NCR_ENET_OSC_EN);
 #endif
        platform_set_drvdata(pdev, ndev);
        ret = smc_enable_device(pdev);
index be67baf..3a18501 100644 (file)
  * Define your architecture specific bus configuration parameters here.
  */
 
-#if defined(CONFIG_ARCH_LUBBOCK) ||\
-    defined(CONFIG_MACH_MAINSTONE) ||\
-    defined(CONFIG_MACH_ZYLONITE) ||\
-    defined(CONFIG_MACH_LITTLETON) ||\
-    defined(CONFIG_MACH_ZYLONITE2) ||\
-    defined(CONFIG_ARCH_VIPER) ||\
-    defined(CONFIG_MACH_STARGATE2) ||\
-    defined(CONFIG_ARCH_VERSATILE)
+#if defined(CONFIG_ARM)
 
 #include <asm/mach-types.h>
 
 /* We actually can't write halfwords properly if not word aligned */
 static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 {
-       if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) {
-               unsigned int v = val << 16;
-               v |= readl(ioaddr + (reg & ~2)) & 0xffff;
-               writel(v, ioaddr + (reg & ~2));
-       } else {
-               writew(val, ioaddr + reg);
-       }
-}
-
-#elif defined(CONFIG_SA1100_PLEB)
-/* We can only do 16-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (-1)
-
-#elif defined(CONFIG_SA1100_ASSABET)
-
-#include <mach/neponset.h>
-
-/* We can only do 8-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      0
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-/* The first two address lines aren't connected... */
-#define SMC_IO_SHIFT           2
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
-#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-#elif  defined(CONFIG_MACH_LOGICPD_PXA270) ||  \
-       defined(CONFIG_MACH_NOMADIK_8815NHK)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#elif  defined(CONFIG_ARCH_INNOKOM) || \
-       defined(CONFIG_ARCH_PXA_IDP) || \
-       defined(CONFIG_ARCH_RAMSES) || \
-       defined(CONFIG_ARCH_PCM027)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-#define SMC_USE_PXA_DMA                1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-/* We actually can't write halfwords properly if not word aligned */
-static inline void
-SMC_outw(u16 val, void __iomem *ioaddr, int reg)
-{
-       if (reg & 2) {
+       if ((machine_is_mainstone() || machine_is_stargate2() ||
+            machine_is_pxa_idp()) && reg & 2) {
                unsigned int v = val << 16;
                v |= readl(ioaddr + (reg & ~2)) & 0xffff;
                writel(v, ioaddr + (reg & ~2));
@@ -237,20 +143,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define RPC_LSA_DEFAULT         RPC_LED_100_10
 #define RPC_LSB_DEFAULT         RPC_LED_TX_RX
 
-#elif defined(CONFIG_ARCH_MSM)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          IRQF_TRIGGER_HIGH
-
 #elif defined(CONFIG_COLDFIRE)
 
 #define SMC_CAN_USE_8BIT       0
index 55e89b3..a0ea84f 100644 (file)
@@ -310,11 +310,11 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
                spin_lock_irqsave(&priv->lock, flags);
                if (!priv->eee_active) {
                        priv->eee_active = 1;
-                       init_timer(&priv->eee_ctrl_timer);
-                       priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
-                       priv->eee_ctrl_timer.data = (unsigned long)priv;
-                       priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer);
-                       add_timer(&priv->eee_ctrl_timer);
+                       setup_timer(&priv->eee_ctrl_timer,
+                                   stmmac_eee_ctrl_timer,
+                                   (unsigned long)priv);
+                       mod_timer(&priv->eee_ctrl_timer,
+                                 STMMAC_LPI_T(eee_timer));
 
                        priv->hw->mac->set_eee_timer(priv->hw,
                                                     STMMAC_DEFAULT_LIT_LS,
index fb846eb..f9b42f1 100644 (file)
@@ -272,6 +272,37 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
        struct stmmac_priv *priv = NULL;
        struct plat_stmmacenet_data *plat_dat = NULL;
        const char *mac = NULL;
+       int irq, wol_irq, lpi_irq;
+
+       /* Get IRQ information early to have an ability to ask for deferred
+        * probe if needed before we went too far with resource allocation.
+        */
+       irq = platform_get_irq_byname(pdev, "macirq");
+       if (irq < 0) {
+               if (irq != -EPROBE_DEFER) {
+                       dev_err(dev,
+                               "MAC IRQ configuration information not found\n");
+               }
+               return irq;
+       }
+
+       /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
+        * The external wake up irq can be passed through the platform code
+        * named as "eth_wake_irq"
+        *
+        * In case the wake up interrupt is not passed from the platform
+        * so the driver will continue to use the mac irq (ndev->irq)
+        */
+       wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+       if (wol_irq < 0) {
+               if (wol_irq == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               wol_irq = irq;
+       }
+
+       lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
+       if (lpi_irq == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        addr = devm_ioremap_resource(dev, res);
@@ -323,39 +354,15 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
                return PTR_ERR(priv);
        }
 
+       /* Copy IRQ values to priv structure which is now avaialble */
+       priv->dev->irq = irq;
+       priv->wol_irq = wol_irq;
+       priv->lpi_irq = lpi_irq;
+
        /* Get MAC address if available (DT) */
        if (mac)
                memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
 
-       /* Get the MAC information */
-       priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
-       if (priv->dev->irq < 0) {
-               if (priv->dev->irq != -EPROBE_DEFER) {
-                       netdev_err(priv->dev,
-                                  "MAC IRQ configuration information not found\n");
-               }
-               return priv->dev->irq;
-       }
-
-       /*
-        * On some platforms e.g. SPEAr the wake up irq differs from the mac irq
-        * The external wake up irq can be passed through the platform code
-        * named as "eth_wake_irq"
-        *
-        * In case the wake up interrupt is not passed from the platform
-        * so the driver will continue to use the mac irq (ndev->irq)
-        */
-       priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
-       if (priv->wol_irq < 0) {
-               if (priv->wol_irq == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-               priv->wol_irq = priv->dev->irq;
-       }
-
-       priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
-       if (priv->lpi_irq == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
-
        platform_set_drvdata(pdev, priv->dev);
 
        pr_debug("STMMAC platform driver registration completed");
index 4b51f90..0c5842a 100644 (file)
@@ -6989,10 +6989,10 @@ static int niu_class_to_ethflow(u64 class, int *flow_type)
                *flow_type = IP_USER_FLOW;
                break;
        default:
-               return 0;
+               return -EINVAL;
        }
 
-       return 1;
+       return 0;
 }
 
 static int niu_ethflow_to_class(int flow_type, u64 *class)
@@ -7198,11 +7198,9 @@ static int niu_get_ethtool_tcam_entry(struct niu *np,
        class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
                TCAM_V4KEY0_CLASS_CODE_SHIFT;
        ret = niu_class_to_ethflow(class, &fsp->flow_type);
-
        if (ret < 0) {
                netdev_info(np->dev, "niu%d: niu_class_to_ethflow failed\n",
                            parent->index);
-               ret = -EINVAL;
                goto out;
        }
 
index 7d8dd0d..a1bbaf6 100644 (file)
@@ -1103,7 +1103,7 @@ static inline void cpsw_add_dual_emac_def_ale_entries(
        cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
                           port_mask, ALE_VLAN, slave->port_vlan, 0);
        cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
-               priv->host_port, ALE_VLAN, slave->port_vlan);
+               priv->host_port, ALE_VLAN | ALE_SECURE, slave->port_vlan);
 }
 
 static void soft_reset_slave(struct cpsw_slave *slave)
@@ -2466,6 +2466,7 @@ static int cpsw_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int cpsw_suspend(struct device *dev)
 {
        struct platform_device  *pdev = to_platform_device(dev);
@@ -2518,11 +2519,9 @@ static int cpsw_resume(struct device *dev)
        }
        return 0;
 }
+#endif
 
-static const struct dev_pm_ops cpsw_pm_ops = {
-       .suspend        = cpsw_suspend,
-       .resume         = cpsw_resume,
-};
+static SIMPLE_DEV_PM_OPS(cpsw_pm_ops, cpsw_suspend, cpsw_resume);
 
 static const struct of_device_id cpsw_of_mtable[] = {
        { .compatible = "ti,cpsw", },
index 98655b4..c00084d 100644 (file)
@@ -423,6 +423,7 @@ static int davinci_mdio_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int davinci_mdio_suspend(struct device *dev)
 {
        struct davinci_mdio_data *data = dev_get_drvdata(dev);
@@ -464,10 +465,10 @@ static int davinci_mdio_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static const struct dev_pm_ops davinci_mdio_pm_ops = {
-       .suspend_late   = davinci_mdio_suspend,
-       .resume_early   = davinci_mdio_resume,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(davinci_mdio_suspend, davinci_mdio_resume)
 };
 
 #if IS_ENABLED(CONFIG_OF)
index a495931..0e0fbb5 100644 (file)
@@ -498,9 +498,9 @@ static int w5100_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (rx_count < budget) {
+               napi_complete(napi);
                w5100_write(priv, W5100_IMR, IR_S0);
                mmiowb();
-               napi_complete(napi);
        }
 
        return rx_count;
index 09322d9..4b31000 100644 (file)
@@ -418,9 +418,9 @@ static int w5300_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (rx_count < budget) {
+               napi_complete(napi);
                w5300_write(priv, W5300_IMR, IR_S0);
                mmiowb();
-               napi_complete(napi);
        }
 
        return rx_count;
index f7e0f0f..9e16a28 100644 (file)
@@ -938,7 +938,7 @@ static void eth_set_mcast_list(struct net_device *dev)
        int i;
        static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
-       if (dev->flags & IFF_ALLMULTI) {
+       if ((dev->flags & IFF_ALLMULTI) && !(dev->flags & IFF_PROMISC)) {
                for (i = 0; i < ETH_ALEN; i++) {
                        __raw_writel(allmulti[i], &port->regs->mcast_addr[i]);
                        __raw_writel(allmulti[i], &port->regs->mcast_mask[i]);
index 924ea98..54549a6 100644 (file)
@@ -114,7 +114,9 @@ unsigned int ipvlan_mac_hash(const unsigned char *addr);
 rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb);
 int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev);
 void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr);
-bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6);
+struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
+                                  const void *iaddr, bool is_v6);
+bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6);
 struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
                                        const void *iaddr, bool is_v6);
 void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync);
index 2a17500..b7877a1 100644 (file)
@@ -81,19 +81,20 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)
        hash = (addr->atype == IPVL_IPV6) ?
               ipvlan_get_v6_hash(&addr->ip6addr) :
               ipvlan_get_v4_hash(&addr->ip4addr);
-       hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
+       if (hlist_unhashed(&addr->hlnode))
+               hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
 }
 
 void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync)
 {
-       hlist_del_rcu(&addr->hlnode);
+       hlist_del_init_rcu(&addr->hlnode);
        if (sync)
                synchronize_rcu();
 }
 
-bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
+struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
+                                  const void *iaddr, bool is_v6)
 {
-       struct ipvl_port *port = ipvlan->port;
        struct ipvl_addr *addr;
 
        list_for_each_entry(addr, &ipvlan->addrs, anode) {
@@ -101,12 +102,21 @@ bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
                    ipv6_addr_equal(&addr->ip6addr, iaddr)) ||
                    (!is_v6 && addr->atype == IPVL_IPV4 &&
                    addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr))
-                       return true;
+                       return addr;
        }
+       return NULL;
+}
+
+bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6)
+{
+       struct ipvl_dev *ipvlan;
 
-       if (ipvlan_ht_addr_lookup(port, iaddr, is_v6))
-               return true;
+       ASSERT_RTNL();
 
+       list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+               if (ipvlan_find_addr(ipvlan, iaddr, is_v6))
+                       return true;
+       }
        return false;
 }
 
@@ -192,7 +202,8 @@ static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb,
        if (skb->protocol == htons(ETH_P_PAUSE))
                return;
 
-       list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
                if (local && (ipvlan == in_dev))
                        continue;
 
@@ -219,6 +230,7 @@ static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb,
 mcast_acct:
                ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true);
        }
+       rcu_read_unlock();
 
        /* Locally generated? ...Forward a copy to the main-device as
         * well. On the RX side we'll ignore it (wont give it to any
index 4f4099d..4fa1420 100644 (file)
@@ -505,7 +505,7 @@ static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
        if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
                list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) {
                        ipvlan_ht_addr_del(addr, !dev->dismantle);
-                       list_del_rcu(&addr->anode);
+                       list_del(&addr->anode);
                }
        }
        list_del_rcu(&ipvlan->pnode);
@@ -607,7 +607,7 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
 {
        struct ipvl_addr *addr;
 
-       if (ipvlan_addr_busy(ipvlan, ip6_addr, true)) {
+       if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) {
                netif_err(ipvlan, ifup, ipvlan->dev,
                          "Failed to add IPv6=%pI6c addr for %s intf\n",
                          ip6_addr, ipvlan->dev->name);
@@ -620,9 +620,13 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
        addr->master = ipvlan;
        memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr));
        addr->atype = IPVL_IPV6;
-       list_add_tail_rcu(&addr->anode, &ipvlan->addrs);
+       list_add_tail(&addr->anode, &ipvlan->addrs);
        ipvlan->ipv6cnt++;
-       ipvlan_ht_addr_add(ipvlan, addr);
+       /* If the interface is not up, the address will be added to the hash
+        * list by ipvlan_open.
+        */
+       if (netif_running(ipvlan->dev))
+               ipvlan_ht_addr_add(ipvlan, addr);
 
        return 0;
 }
@@ -631,12 +635,12 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
 {
        struct ipvl_addr *addr;
 
-       addr = ipvlan_ht_addr_lookup(ipvlan->port, ip6_addr, true);
+       addr = ipvlan_find_addr(ipvlan, ip6_addr, true);
        if (!addr)
                return;
 
        ipvlan_ht_addr_del(addr, true);
-       list_del_rcu(&addr->anode);
+       list_del(&addr->anode);
        ipvlan->ipv6cnt--;
        WARN_ON(ipvlan->ipv6cnt < 0);
        kfree_rcu(addr, rcu);
@@ -675,7 +679,7 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
 {
        struct ipvl_addr *addr;
 
-       if (ipvlan_addr_busy(ipvlan, ip4_addr, false)) {
+       if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) {
                netif_err(ipvlan, ifup, ipvlan->dev,
                          "Failed to add IPv4=%pI4 on %s intf.\n",
                          ip4_addr, ipvlan->dev->name);
@@ -688,9 +692,13 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
        addr->master = ipvlan;
        memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr));
        addr->atype = IPVL_IPV4;
-       list_add_tail_rcu(&addr->anode, &ipvlan->addrs);
+       list_add_tail(&addr->anode, &ipvlan->addrs);
        ipvlan->ipv4cnt++;
-       ipvlan_ht_addr_add(ipvlan, addr);
+       /* If the interface is not up, the address will be added to the hash
+        * list by ipvlan_open.
+        */
+       if (netif_running(ipvlan->dev))
+               ipvlan_ht_addr_add(ipvlan, addr);
        ipvlan_set_broadcast_mac_filter(ipvlan, true);
 
        return 0;
@@ -700,12 +708,12 @@ static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
 {
        struct ipvl_addr *addr;
 
-       addr = ipvlan_ht_addr_lookup(ipvlan->port, ip4_addr, false);
+       addr = ipvlan_find_addr(ipvlan, ip4_addr, false);
        if (!addr)
                return;
 
        ipvlan_ht_addr_del(addr, true);
-       list_del_rcu(&addr->anode);
+       list_del(&addr->anode);
        ipvlan->ipv4cnt--;
        WARN_ON(ipvlan->ipv4cnt < 0);
        if (!ipvlan->ipv4cnt)
index e40fdfc..27ecc5c 100644 (file)
@@ -654,11 +654,14 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q,
        } /* else everything is zero */
 }
 
+/* Neighbour code has some assumptions on HH_DATA_MOD alignment */
+#define MACVTAP_RESERVE HH_DATA_OFF(ETH_HLEN)
+
 /* Get packet from user space buffer */
 static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                                struct iov_iter *from, int noblock)
 {
-       int good_linear = SKB_MAX_HEAD(NET_IP_ALIGN);
+       int good_linear = SKB_MAX_HEAD(MACVTAP_RESERVE);
        struct sk_buff *skb;
        struct macvlan_dev *vlan;
        unsigned long total_len = iov_iter_count(from);
@@ -722,7 +725,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                        linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
        }
 
-       skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen,
+       skb = macvtap_alloc_skb(&q->sk, MACVTAP_RESERVE, copylen,
                                linear, noblock, &err);
        if (!skb)
                goto err;
index 9e3af54..32efbd4 100644 (file)
@@ -92,6 +92,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define XGBE_PHY_CDR_RATE_PROPERTY     "amd,serdes-cdr-rate"
 #define XGBE_PHY_PQ_SKEW_PROPERTY      "amd,serdes-pq-skew"
 #define XGBE_PHY_TX_AMP_PROPERTY       "amd,serdes-tx-amp"
+#define XGBE_PHY_DFE_CFG_PROPERTY      "amd,serdes-dfe-tap-config"
+#define XGBE_PHY_DFE_ENA_PROPERTY      "amd,serdes-dfe-tap-enable"
 
 #define XGBE_PHY_SPEEDS                        3
 #define XGBE_PHY_SPEED_1000            0
@@ -177,10 +179,12 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_10000_BLWC               0
 #define SPEED_10000_CDR                        0x7
 #define SPEED_10000_PLL                        0x1
-#define SPEED_10000_PQ                 0x1e
+#define SPEED_10000_PQ                 0x12
 #define SPEED_10000_RATE               0x0
 #define SPEED_10000_TXAMP              0xa
 #define SPEED_10000_WORD               0x7
+#define SPEED_10000_DFE_TAP_CONFIG     0x1
+#define SPEED_10000_DFE_TAP_ENABLE     0x7f
 
 #define SPEED_2500_BLWC                        1
 #define SPEED_2500_CDR                 0x2
@@ -189,6 +193,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_2500_RATE                        0x1
 #define SPEED_2500_TXAMP               0xf
 #define SPEED_2500_WORD                        0x1
+#define SPEED_2500_DFE_TAP_CONFIG      0x3
+#define SPEED_2500_DFE_TAP_ENABLE      0x0
 
 #define SPEED_1000_BLWC                        1
 #define SPEED_1000_CDR                 0x2
@@ -197,16 +203,25 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_1000_RATE                        0x3
 #define SPEED_1000_TXAMP               0xf
 #define SPEED_1000_WORD                        0x1
+#define SPEED_1000_DFE_TAP_CONFIG      0x3
+#define SPEED_1000_DFE_TAP_ENABLE      0x0
 
 /* SerDes RxTx register offsets */
+#define RXTX_REG6                      0x0018
 #define RXTX_REG20                     0x0050
+#define RXTX_REG22                     0x0058
 #define RXTX_REG114                    0x01c8
+#define RXTX_REG129                    0x0204
 
 /* SerDes RxTx register entry bit positions and sizes */
+#define RXTX_REG6_RESETB_RXD_INDEX     8
+#define RXTX_REG6_RESETB_RXD_WIDTH     1
 #define RXTX_REG20_BLWC_ENA_INDEX      2
 #define RXTX_REG20_BLWC_ENA_WIDTH      1
 #define RXTX_REG114_PQ_REG_INDEX       9
 #define RXTX_REG114_PQ_REG_WIDTH       7
+#define RXTX_REG129_RXDFE_CONFIG_INDEX 14
+#define RXTX_REG129_RXDFE_CONFIG_WIDTH 2
 
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
@@ -333,6 +348,18 @@ static const u32 amd_xgbe_phy_serdes_tx_amp[] = {
        SPEED_10000_TXAMP,
 };
 
+static const u32 amd_xgbe_phy_serdes_dfe_tap_cfg[] = {
+       SPEED_1000_DFE_TAP_CONFIG,
+       SPEED_2500_DFE_TAP_CONFIG,
+       SPEED_10000_DFE_TAP_CONFIG,
+};
+
+static const u32 amd_xgbe_phy_serdes_dfe_tap_ena[] = {
+       SPEED_1000_DFE_TAP_ENABLE,
+       SPEED_2500_DFE_TAP_ENABLE,
+       SPEED_10000_DFE_TAP_ENABLE,
+};
+
 enum amd_xgbe_phy_an {
        AMD_XGBE_AN_READY = 0,
        AMD_XGBE_AN_PAGE_RECEIVED,
@@ -393,6 +420,8 @@ struct amd_xgbe_phy_priv {
        u32 serdes_cdr_rate[XGBE_PHY_SPEEDS];
        u32 serdes_pq_skew[XGBE_PHY_SPEEDS];
        u32 serdes_tx_amp[XGBE_PHY_SPEEDS];
+       u32 serdes_dfe_tap_cfg[XGBE_PHY_SPEEDS];
+       u32 serdes_dfe_tap_ena[XGBE_PHY_SPEEDS];
 
        /* Auto-negotiation state machine support */
        struct mutex an_mutex;
@@ -481,11 +510,16 @@ static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev)
                status = XSIR0_IOREAD(priv, SIR0_STATUS);
                if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
                    XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
-                       return;
+                       goto rx_reset;
        }
 
        netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n",
                   status);
+
+rx_reset:
+       /* Perform Rx reset for the DFE changes */
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 0);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 1);
 }
 
 static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
@@ -534,6 +568,10 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_10000]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_10000]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_10000]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -586,6 +624,10 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_2500]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_2500]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_2500]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -638,6 +680,10 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_1000]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_1000]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_1000]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -1668,6 +1714,38 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev)
                       sizeof(priv->serdes_tx_amp));
        }
 
+       if (device_property_present(phy_dev, XGBE_PHY_DFE_CFG_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_PHY_DFE_CFG_PROPERTY,
+                                                    priv->serdes_dfe_tap_cfg,
+                                                    XGBE_PHY_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_PHY_DFE_CFG_PROPERTY);
+                       goto err_sir1;
+               }
+       } else {
+               memcpy(priv->serdes_dfe_tap_cfg,
+                      amd_xgbe_phy_serdes_dfe_tap_cfg,
+                      sizeof(priv->serdes_dfe_tap_cfg));
+       }
+
+       if (device_property_present(phy_dev, XGBE_PHY_DFE_ENA_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_PHY_DFE_ENA_PROPERTY,
+                                                    priv->serdes_dfe_tap_ena,
+                                                    XGBE_PHY_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_PHY_DFE_ENA_PROPERTY);
+                       goto err_sir1;
+               }
+       } else {
+               memcpy(priv->serdes_dfe_tap_ena,
+                      amd_xgbe_phy_serdes_dfe_tap_ena,
+                      sizeof(priv->serdes_dfe_tap_ena));
+       }
+
        phydev->priv = priv;
 
        if (!priv->adev || acpi_disabled)
index cdcac6a..52cd8db 100644 (file)
@@ -235,6 +235,25 @@ static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
        return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
 }
 
+/**
+ * phy_check_valid - check if there is a valid PHY setting which matches
+ *                  speed, duplex, and feature mask
+ * @speed: speed to match
+ * @duplex: duplex to match
+ * @features: A mask of the valid settings
+ *
+ * Description: Returns true if there is a valid setting, false otherwise.
+ */
+static inline bool phy_check_valid(int speed, int duplex, u32 features)
+{
+       unsigned int idx;
+
+       idx = phy_find_valid(phy_find_setting(speed, duplex), features);
+
+       return settings[idx].speed == speed && settings[idx].duplex == duplex &&
+               (settings[idx].setting & features);
+}
+
 /**
  * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
  * @phydev: the target phy_device struct
@@ -1045,7 +1064,6 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
                int status;
-               unsigned int idx;
 
                /* Read phy status to properly get the right settings */
                status = phy_read_status(phydev);
@@ -1077,8 +1095,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
 
                adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
                lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
-               idx = phy_find_setting(phydev->speed, phydev->duplex);
-               if (!(lp & adv & settings[idx].setting))
+               if (!phy_check_valid(phydev->speed, phydev->duplex, lp & adv))
                        goto eee_exit_err;
 
                if (clk_stop_enable) {
index 0e62274..7d39484 100644 (file)
@@ -43,9 +43,7 @@
 
 static struct team_port *team_port_get_rcu(const struct net_device *dev)
 {
-       struct team_port *port = rcu_dereference(dev->rx_handler_data);
-
-       return team_port_exists(dev) ? port : NULL;
+       return rcu_dereference(dev->rx_handler_data);
 }
 
 static struct team_port *team_port_get_rtnl(const struct net_device *dev)
@@ -1732,11 +1730,11 @@ static int team_set_mac_address(struct net_device *dev, void *p)
        if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       rcu_read_lock();
-       list_for_each_entry_rcu(port, &team->port_list, list)
+       mutex_lock(&team->lock);
+       list_for_each_entry(port, &team->port_list, list)
                if (team->ops.port_change_dev_addr)
                        team->ops.port_change_dev_addr(team, port);
-       rcu_read_unlock();
+       mutex_unlock(&team->lock);
        return 0;
 }
 
index 3bd9678..7ba8d08 100644 (file)
@@ -161,6 +161,7 @@ config USB_NET_AX8817X
            * Linksys USB200M
            * Netgear FA120
            * Sitecom LN-029
+           * Sitecom LN-028
            * Intellinet USB 2.0 Ethernet
            * ST Lab USB 2.0 Ethernet
            * TrendNet TU2-ET100
index 5c55f11..75d6f26 100644 (file)
@@ -188,6 +188,8 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
                skb_put(skb, sizeof(padbytes));
        }
+
+       usbnet_set_skb_tx_stats(skb, 1, 0);
        return skb;
 }
 
index bf49792..1173a24 100644 (file)
@@ -978,6 +978,10 @@ static const struct usb_device_id  products [] = {
        // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter"
        USB_DEVICE (0x0df6, 0x0056),
        .driver_info =  (unsigned long) &ax88178_info,
+}, {
+       // Sitecom LN-028 "USB 2.0 10/100/1000 Ethernet adapter"
+       USB_DEVICE (0x0df6, 0x061c),
+       .driver_info =  (unsigned long) &ax88178_info,
 }, {
        // corega FEther USB2-TX
        USB_DEVICE (0x07aa, 0x0017),
index 9311a08..4545e78 100644 (file)
@@ -522,6 +522,7 @@ static const struct driver_info wwan_info = {
 #define DELL_VENDOR_ID         0x413C
 #define REALTEK_VENDOR_ID      0x0bda
 #define SAMSUNG_VENDOR_ID      0x04e8
+#define LENOVO_VENDOR_ID       0x17ef
 
 static const struct usb_device_id      products[] = {
 /* BLACKLIST !!
@@ -702,6 +703,13 @@ static const struct usb_device_id  products[] = {
        .driver_info = 0,
 },
 
+/* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
 /* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
index 80a844e..c3e4da9 100644 (file)
@@ -1172,17 +1172,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
 
        /* return skb */
        ctx->tx_curr_skb = NULL;
-       dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
 
        /* keep private stats: framing overhead and number of NTBs */
        ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload;
        ctx->tx_ntbs++;
 
-       /* usbnet has already counted all the framing overhead.
+       /* usbnet will count all the framing overhead by default.
         * Adjust the stats so that the tx_bytes counter show real
         * payload data instead.
         */
-       dev->net->stats.tx_bytes -= skb_out->len - ctx->tx_curr_frame_payload;
+       usbnet_set_skb_tx_stats(skb_out, n,
+                               ctx->tx_curr_frame_payload - skb_out->len);
 
        return skb_out;
 
index 3eed708..1762ad3 100644 (file)
@@ -46,8 +46,7 @@ enum cx82310_status {
 };
 
 #define CMD_PACKET_SIZE        64
-/* first command after power on can take around 8 seconds */
-#define CMD_TIMEOUT    15000
+#define CMD_TIMEOUT    100
 #define CMD_REPLY_RETRY 5
 
 #define CX82310_MTU    1514
@@ -78,8 +77,9 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
        ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf,
                           CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);
        if (ret < 0) {
-               dev_err(&dev->udev->dev, "send command %#x: error %d\n",
-                       cmd, ret);
+               if (cmd != CMD_GET_LINK_STATUS)
+                       dev_err(&dev->udev->dev, "send command %#x: error %d\n",
+                               cmd, ret);
                goto end;
        }
 
@@ -90,8 +90,10 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
                                           buf, CMD_PACKET_SIZE, &actual_len,
                                           CMD_TIMEOUT);
                        if (ret < 0) {
-                               dev_err(&dev->udev->dev,
-                                       "reply receive error %d\n", ret);
+                               if (cmd != CMD_GET_LINK_STATUS)
+                                       dev_err(&dev->udev->dev,
+                                               "reply receive error %d\n",
+                                               ret);
                                goto end;
                        }
                        if (actual_len > 0)
@@ -134,6 +136,8 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        int ret;
        char buf[15];
        struct usb_device *udev = dev->udev;
+       u8 link[3];
+       int timeout = 50;
 
        /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */
        if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0
@@ -160,6 +164,20 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        if (!dev->partial_data)
                return -ENOMEM;
 
+       /* wait for firmware to become ready (indicated by the link being up) */
+       while (--timeout) {
+               ret = cx82310_cmd(dev, CMD_GET_LINK_STATUS, true, NULL, 0,
+                                 link, sizeof(link));
+               /* the command can time out during boot - it's not an error */
+               if (!ret && link[0] == 1 && link[2] == 1)
+                       break;
+               msleep(500);
+       };
+       if (!timeout) {
+               dev_err(&udev->dev, "firmware not ready in time\n");
+               return -ETIMEDOUT;
+       }
+
        /* enable ethernet mode (?) */
        ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
        if (ret) {
@@ -300,9 +318,18 @@ static const struct driver_info    cx82310_info = {
        .tx_fixup       = cx82310_tx_fixup,
 };
 
+#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+                      USB_DEVICE_ID_MATCH_DEV_INFO, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bDeviceClass = (cl), \
+       .bDeviceSubClass = (sc), \
+       .bDeviceProtocol = (pr)
+
 static const struct usb_device_id products[] = {
        {
-               USB_DEVICE_AND_INTERFACE_INFO(0x0572, 0xcb01, 0xff, 0, 0),
+               USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0),
                .driver_info = (unsigned long) &cx82310_info
        },
        { },
index 9cdfb3f..778e915 100644 (file)
@@ -1594,7 +1594,7 @@ hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
                }
                cprev = cnow;
        }
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        remove_wait_queue(&tiocmget->waitq, &wait);
 
        return ret;
index 3d18bb0..1bfe0fc 100644 (file)
@@ -134,6 +134,11 @@ static const struct usb_device_id  products [] = {
 }, {
        USB_DEVICE(0x050d, 0x258a),     /* Belkin F5U258/F5U279 (PL-25A1) */
        .driver_info =  (unsigned long) &prolific_info,
+}, {
+       USB_DEVICE(0x3923, 0x7825),     /* National Instruments USB
+                                        * Host-to-Host Cable
+                                        */
+       .driver_info =  (unsigned long) &prolific_info,
 },
 
        { },            // END
index 438fc6b..9f7c0ab 100644 (file)
@@ -492,6 +492,7 @@ enum rtl8152_flags {
 /* Define these values to match your device */
 #define VENDOR_ID_REALTEK              0x0bda
 #define VENDOR_ID_SAMSUNG              0x04e8
+#define VENDOR_ID_LENOVO               0x17ef
 
 #define MCU_TYPE_PLA                   0x0100
 #define MCU_TYPE_USB                   0x0000
@@ -4037,6 +4038,7 @@ static struct usb_device_id rtl8152_table[] = {
        {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)},
        {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
        {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
+       {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x7205)},
        {}
 };
 
index b94a0fb..953de13 100644 (file)
@@ -144,6 +144,7 @@ static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                skb_put(skb, sizeof(padbytes));
        }
 
+       usbnet_set_skb_tx_stats(skb, 1, 0);
        return skb;
 }
 
index 449835f..777757a 100644 (file)
@@ -1188,8 +1188,7 @@ static void tx_complete (struct urb *urb)
        struct usbnet           *dev = entry->dev;
 
        if (urb->status == 0) {
-               if (!(dev->driver_info->flags & FLAG_MULTI_PACKET))
-                       dev->net->stats.tx_packets++;
+               dev->net->stats.tx_packets += entry->packets;
                dev->net->stats.tx_bytes += entry->length;
        } else {
                dev->net->stats.tx_errors++;
@@ -1347,7 +1346,19 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                } else
                        urb->transfer_flags |= URB_ZERO_PACKET;
        }
-       entry->length = urb->transfer_buffer_length = length;
+       urb->transfer_buffer_length = length;
+
+       if (info->flags & FLAG_MULTI_PACKET) {
+               /* Driver has set number of packets and a length delta.
+                * Calculate the complete length and ensure that it's
+                * positive.
+                */
+               entry->length += length;
+               if (WARN_ON_ONCE(entry->length <= 0))
+                       entry->length = length;
+       } else {
+               usbnet_set_skb_tx_stats(skb, 1, length);
+       }
 
        spin_lock_irqsave(&dev->txq.lock, flags);
        retval = usb_autopm_get_interface_async(dev->intf);
index f1ff366..59b0e97 100644 (file)
@@ -1448,8 +1448,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
 {
        int i;
 
-       for (i = 0; i < vi->max_queue_pairs; i++)
+       for (i = 0; i < vi->max_queue_pairs; i++) {
+               napi_hash_del(&vi->rq[i].napi);
                netif_napi_del(&vi->rq[i].napi);
+       }
 
        kfree(vi->rq);
        kfree(vi->sq);
@@ -1948,11 +1950,8 @@ static int virtnet_freeze(struct virtio_device *vdev)
        cancel_delayed_work_sync(&vi->refill);
 
        if (netif_running(vi->dev)) {
-               for (i = 0; i < vi->max_queue_pairs; i++) {
+               for (i = 0; i < vi->max_queue_pairs; i++)
                        napi_disable(&vi->rq[i].napi);
-                       napi_hash_del(&vi->rq[i].napi);
-                       netif_napi_del(&vi->rq[i].napi);
-               }
        }
 
        remove_vq_common(vi);
index 1e0a775..f8528a4 100644 (file)
@@ -1218,7 +1218,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                        goto drop;
 
                flags &= ~VXLAN_HF_RCO;
-               vni &= VXLAN_VID_MASK;
+               vni &= VXLAN_VNI_MASK;
        }
 
        /* For backwards compatibility, only allow reserved fields to be
@@ -1239,7 +1239,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                flags &= ~VXLAN_GBP_USED_BITS;
        }
 
-       if (flags || (vni & ~VXLAN_VID_MASK)) {
+       if (flags || vni & ~VXLAN_VNI_MASK) {
                /* If there are any unprocessed flags remaining treat
                 * this as a malformed packet. This behavior diverges from
                 * VXLAN RFC (RFC7348) which stipulates that bits in reserved
index 83c39e2..88d121d 100644 (file)
@@ -806,21 +806,21 @@ static ssize_t cosa_read(struct file *file,
        spin_lock_irqsave(&cosa->lock, flags);
        add_wait_queue(&chan->rxwaitq, &wait);
        while (!chan->rx_status) {
-               current->state = TASK_INTERRUPTIBLE;
+               set_current_state(TASK_INTERRUPTIBLE);
                spin_unlock_irqrestore(&cosa->lock, flags);
                schedule();
                spin_lock_irqsave(&cosa->lock, flags);
                if (signal_pending(current) && chan->rx_status == 0) {
                        chan->rx_status = 1;
                        remove_wait_queue(&chan->rxwaitq, &wait);
-                       current->state = TASK_RUNNING;
+                       __set_current_state(TASK_RUNNING);
                        spin_unlock_irqrestore(&cosa->lock, flags);
                        mutex_unlock(&chan->rlock);
                        return -ERESTARTSYS;
                }
        }
        remove_wait_queue(&chan->rxwaitq, &wait);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        kbuf = chan->rxdata;
        count = chan->rxsize;
        spin_unlock_irqrestore(&cosa->lock, flags);
@@ -890,14 +890,14 @@ static ssize_t cosa_write(struct file *file,
        spin_lock_irqsave(&cosa->lock, flags);
        add_wait_queue(&chan->txwaitq, &wait);
        while (!chan->tx_status) {
-               current->state = TASK_INTERRUPTIBLE;
+               set_current_state(TASK_INTERRUPTIBLE);
                spin_unlock_irqrestore(&cosa->lock, flags);
                schedule();
                spin_lock_irqsave(&cosa->lock, flags);
                if (signal_pending(current) && chan->tx_status == 0) {
                        chan->tx_status = 1;
                        remove_wait_queue(&chan->txwaitq, &wait);
-                       current->state = TASK_RUNNING;
+                       __set_current_state(TASK_RUNNING);
                        chan->tx_status = 1;
                        spin_unlock_irqrestore(&cosa->lock, flags);
                        up(&chan->wsem);
@@ -905,7 +905,7 @@ static ssize_t cosa_write(struct file *file,
                }
        }
        remove_wait_queue(&chan->txwaitq, &wait);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        up(&chan->wsem);
        spin_unlock_irqrestore(&cosa->lock, flags);
        kfree(kbuf);
index cb366ad..f50a6bc 100644 (file)
@@ -219,12 +219,15 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        struct ath_buf *bf = avp->av_bcbuf;
+       struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
 
        ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
                avp->av_bslot);
 
        tasklet_disable(&sc->bcon_tasklet);
 
+       cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
+
        if (bf && bf->bf_mpdu) {
                struct sk_buff *skb = bf->bf_mpdu;
                dma_unmap_single(sc->dev, bf->bf_buf_addr,
@@ -521,8 +524,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
        }
 
        if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-               if ((vif->type != NL80211_IFTYPE_AP) ||
-                   (sc->nbcnvifs > 1)) {
+               if (vif->type != NL80211_IFTYPE_AP) {
                        ath_dbg(common, CONFIG,
                                "An AP interface is already present !\n");
                        return false;
@@ -616,12 +618,14 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
         * enabling/disabling SWBA.
         */
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
-               if (!bss_conf->enable_beacon &&
-                   (sc->nbcnvifs <= 1)) {
-                       cur_conf->enable_beacon = false;
-               } else if (bss_conf->enable_beacon) {
-                       cur_conf->enable_beacon = true;
-                       ath9k_cache_beacon_config(sc, ctx, bss_conf);
+               bool enabled = cur_conf->enable_beacon;
+
+               if (!bss_conf->enable_beacon) {
+                       cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
+               } else {
+                       cur_conf->enable_beacon |= BIT(avp->av_bslot);
+                       if (!enabled)
+                               ath9k_cache_beacon_config(sc, ctx, bss_conf);
                }
        }
 
index 2b79a56..d237373 100644 (file)
@@ -54,7 +54,7 @@ struct ath_beacon_config {
        u16 dtim_period;
        u16 bmiss_timeout;
        u8 dtim_count;
-       bool enable_beacon;
+       u8 enable_beacon;
        bool ibss_creator;
        u32 nexttbtt;
        u32 intval;
index 60aa8d7..8529014 100644 (file)
@@ -424,7 +424,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->power_mode = ATH9K_PM_UNDEFINED;
        ah->htc_reset_init = true;
 
-       ah->tpc_enabled = true;
+       ah->tpc_enabled = false;
 
        ah->ani_function = ATH9K_ANI_ALL;
        if (!AR_SREV_9300_20_OR_LATER(ah))
index ccbdb05..75345c1 100644 (file)
@@ -5370,6 +5370,7 @@ static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy,
        case 0x432a: /* BCM4321 */
        case 0x432d: /* BCM4322 */
        case 0x4352: /* BCM43222 */
+       case 0x435a: /* BCM43228 */
        case 0x4333: /* BCM4331 */
        case 0x43a2: /* BCM4360 */
        case 0x43b3: /* BCM4352 */
index defb7a4..7748a1c 100644 (file)
@@ -126,7 +126,8 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
        if (drvr->bus_if->wowl_supported)
                brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
-       brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
+       if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
+               brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
 
        /* set chip related quirks */
        switch (drvr->bus_if->chip) {
index 50cdf70..8eff275 100644 (file)
@@ -39,13 +39,22 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
        void *dcmd_buf = NULL, *wr_pointer;
        u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
 
-       brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set,
-                 cmdhdr->len);
+       if (len < sizeof(*cmdhdr)) {
+               brcmf_err("vendor command too short: %d\n", len);
+               return -EINVAL;
+       }
 
        vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
        ifp = vif->ifp;
 
-       len -= sizeof(struct brcmf_vndr_dcmd_hdr);
+       brcmf_dbg(TRACE, "ifidx=%d, cmd=%d\n", ifp->ifidx, cmdhdr->cmd);
+
+       if (cmdhdr->offset > len) {
+               brcmf_err("bad buffer offset %d > %d\n", cmdhdr->offset, len);
+               return -EINVAL;
+       }
+
+       len -= cmdhdr->offset;
        ret_len = cmdhdr->len;
        if (ret_len > 0 || len > 0) {
                if (len > BRCMF_DCMD_MAXLEN) {
index a6f22c3..3811878 100644 (file)
@@ -708,7 +708,6 @@ struct iwl_priv {
        unsigned long reload_jiffies;
        int reload_count;
        bool ucode_loaded;
-       bool init_ucode_run;            /* Don't run init uCode again */
 
        u8 plcp_delta_threshold;
 
index 47e64e8..cceb026 100644 (file)
@@ -1114,16 +1114,17 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) |
                        BIT(IWL_DEFAULT_CMD_QUEUE_NUM));
 
-       if (vif)
-               scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
-
-       IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues);
-       if (iwlagn_txfifo_flush(priv, scd_queues)) {
-               IWL_ERR(priv, "flush request fail\n");
-               goto done;
+       if (drop) {
+               IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n",
+                                   scd_queues);
+               if (iwlagn_txfifo_flush(priv, scd_queues)) {
+                       IWL_ERR(priv, "flush request fail\n");
+                       goto done;
+               }
        }
+
        IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
+       iwl_trans_wait_tx_queue_empty(priv->trans, scd_queues);
 done:
        mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
index 4dbef7e..5244e43 100644 (file)
@@ -418,9 +418,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
        if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
                return 0;
 
-       if (priv->init_ucode_run)
-               return 0;
-
        iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
                                   calib_complete, ARRAY_SIZE(calib_complete),
                                   iwlagn_wait_calib, priv);
@@ -440,8 +437,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
         */
        ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
                                        UCODE_CALIB_TIMEOUT);
-       if (!ret)
-               priv->init_ucode_run = true;
 
        goto out;
 
index c3817fa..06f6cc0 100644 (file)
@@ -95,7 +95,8 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = {
        .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION,  \
        .base_params = &iwl1000_base_params,                    \
        .eeprom_params = &iwl1000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl1000_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
@@ -121,7 +122,8 @@ const struct iwl_cfg iwl1000_bg_cfg = {
        .base_params = &iwl1000_base_params,                    \
        .eeprom_params = &iwl1000_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl100_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
index 21e5d08..890b95f 100644 (file)
@@ -123,7 +123,9 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
        .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,          \
        .base_params = &iwl2000_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
+
 
 const struct iwl_cfg iwl2000_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
@@ -149,7 +151,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
        .base_params = &iwl2030_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl2030_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
@@ -170,7 +173,8 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
        .base_params = &iwl2000_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl105_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
@@ -197,7 +201,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
        .base_params = &iwl2030_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl135_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
index 332bbed..724194e 100644 (file)
@@ -93,7 +93,8 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = {
        .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION,  \
        .base_params = &iwl5000_base_params,                    \
        .eeprom_params = &iwl5000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl5300_agn_cfg = {
        .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
@@ -158,7 +159,8 @@ const struct iwl_cfg iwl5350_agn_cfg = {
        .base_params = &iwl5000_base_params,                    \
        .eeprom_params = &iwl5000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl5150_agn_cfg = {
        .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
index 8f2c3c8..21b2630 100644 (file)
@@ -145,7 +145,8 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = {
        .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6005_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
@@ -199,7 +200,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
        .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6030_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
@@ -235,7 +237,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
        .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6035_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
@@ -290,7 +293,8 @@ const struct iwl_cfg iwl130_bg_cfg = {
        .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION,  \
        .base_params = &iwl6000_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6000i_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
@@ -322,7 +326,8 @@ const struct iwl_cfg iwl6000i_2bg_cfg = {
        .base_params = &iwl6050_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6050_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
@@ -347,7 +352,8 @@ const struct iwl_cfg iwl6050_2abg_cfg = {
        .base_params = &iwl6050_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6150_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
index 996e7f1..c7154ac 100644 (file)
@@ -1257,6 +1257,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
                                op->name, err);
 #endif
        }
+       kfree(pieces);
        return;
 
  try_again:
index 1ec4d55..7810c41 100644 (file)
@@ -793,7 +793,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
-       if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
+       if (mvmvif->phy_ctxt &&
+           IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
                               mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
index d530ef3..542ee74 100644 (file)
@@ -832,7 +832,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
-       if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
+       if (mvmvif->phy_ctxt &&
+           data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
        IWL_DEBUG_COEX(data->mvm,
index 1ff7ec0..09654e7 100644 (file)
@@ -405,7 +405,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                        &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
 
-               if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER)
+               if ((mvm->fw->ucode_capa.capa[0] &
+                    IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+                   (mvm->fw->ucode_capa.api[0] &
+                    IWL_UCODE_TLV_API_LQ_SS_PARAMS))
                        hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
                                IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
        }
@@ -2215,7 +2218,19 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
 
-       iwl_mvm_cancel_scan(mvm);
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a hw_scan when it's already stopped.  This can
+        * happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_scan_completed() and the userspace called
+        * cancel scan scan before ieee80211_scan_work() could run.
+        * To handle that, simply return if the scan is not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
+           (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+               iwl_mvm_cancel_scan(mvm);
 
        mutex_unlock(&mvm->mutex);
 }
@@ -2559,12 +2574,29 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
        int ret;
 
        mutex_lock(&mvm->mutex);
+
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a sched_scan when it's already stopped.  This
+        * can happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_sched_scan_stopped() and the userspace called
+        * stop sched scan scan before ieee80211_sched_scan_stopped_work()
+        * could run.  To handle this, simply return if the scan is
+        * not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
+           !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+               mutex_unlock(&mvm->mutex);
+               return 0;
+       }
+
        ret = iwl_mvm_scan_offload_stop(mvm, false);
        mutex_unlock(&mvm->mutex);
        iwl_mvm_wait_for_async_handlers(mvm);
 
        return ret;
-
 }
 
 static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
index 194bd1f..078f24c 100644 (file)
@@ -134,9 +134,12 @@ enum rs_column_mode {
 #define MAX_NEXT_COLUMNS 7
 #define MAX_COLUMN_CHECKS 3
 
+struct rs_tx_column;
+
 typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm,
                                     struct ieee80211_sta *sta,
-                                    struct iwl_scale_tbl_info *tbl);
+                                    struct iwl_scale_tbl_info *tbl,
+                                    const struct rs_tx_column *next_col);
 
 struct rs_tx_column {
        enum rs_column_mode mode;
@@ -147,13 +150,15 @@ struct rs_tx_column {
 };
 
 static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                        struct iwl_scale_tbl_info *tbl)
+                        struct iwl_scale_tbl_info *tbl,
+                        const struct rs_tx_column *next_col)
 {
-       return iwl_mvm_bt_coex_is_ant_avail(mvm, tbl->rate.ant);
+       return iwl_mvm_bt_coex_is_ant_avail(mvm, next_col->ant);
 }
 
 static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                         struct iwl_scale_tbl_info *tbl)
+                         struct iwl_scale_tbl_info *tbl,
+                         const struct rs_tx_column *next_col)
 {
        if (!sta->ht_cap.ht_supported)
                return false;
@@ -171,7 +176,8 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 }
 
 static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                         struct iwl_scale_tbl_info *tbl)
+                         struct iwl_scale_tbl_info *tbl,
+                         const struct rs_tx_column *next_col)
 {
        if (!sta->ht_cap.ht_supported)
                return false;
@@ -180,7 +186,8 @@ static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 }
 
 static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                        struct iwl_scale_tbl_info *tbl)
+                        struct iwl_scale_tbl_info *tbl,
+                        const struct rs_tx_column *next_col)
 {
        struct rs_rate *rate = &tbl->rate;
        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
@@ -1271,6 +1278,9 @@ static void rs_mac80211_tx_status(void *mvm_r,
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
+       if (!iwl_mvm_sta_from_mac80211(sta)->vif)
+               return;
+
        if (!ieee80211_is_data(hdr->frame_control) ||
            info->flags & IEEE80211_TX_CTL_NO_ACK)
                return;
@@ -1590,7 +1600,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
 
                for (j = 0; j < MAX_COLUMN_CHECKS; j++) {
                        allow_func = next_col->checks[j];
-                       if (allow_func && !allow_func(mvm, sta, tbl))
+                       if (allow_func && !allow_func(mvm, sta, tbl, next_col))
                                break;
                }
 
@@ -2504,6 +2514,14 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_lq_sta *lq_sta = mvm_sta;
 
+       if (sta && !iwl_mvm_sta_from_mac80211(sta)->vif) {
+               /* if vif isn't initialized mvm doesn't know about
+                * this station, so don't do anything with the it
+                */
+               sta = NULL;
+               mvm_sta = NULL;
+       }
+
        /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
 
        /* Treat uninitialized rate scaling data same as non-existing. */
@@ -2820,6 +2838,9 @@ static void rs_rate_update(void *mvm_r,
                        (struct iwl_op_mode *)mvm_r;
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
 
+       if (!iwl_mvm_sta_from_mac80211(sta)->vif)
+               return;
+
        /* Stop any ongoing aggregations as rs starts off assuming no agg */
        for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
                ieee80211_stop_tx_ba_session(sta, tid);
@@ -3580,9 +3601,15 @@ static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf,
 
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32);
 
-static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
+static void rs_add_debugfs(void *mvm, void *priv_sta, struct dentry *dir)
 {
-       struct iwl_lq_sta *lq_sta = mvm_sta;
+       struct iwl_lq_sta *lq_sta = priv_sta;
+       struct iwl_mvm_sta *mvmsta;
+
+       mvmsta = container_of(lq_sta, struct iwl_mvm_sta, lq_sta);
+
+       if (!mvmsta->vif)
+               return;
 
        debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
                            lq_sta, &rs_sta_dbgfs_scale_table_ops);
index 7e9aa3c..c47c805 100644 (file)
@@ -1128,8 +1128,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_NONE)
                return 0;
 
-       if (iwl_mvm_is_radio_killed(mvm))
+       if (iwl_mvm_is_radio_killed(mvm)) {
+               ret = 0;
                goto out;
+       }
 
        if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
            (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
@@ -1148,16 +1150,14 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
                IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
                               sched ? "offloaded " : "", ret);
                iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
-               return ret;
+               goto out;
        }
 
        IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
                       sched ? "offloaded " : "");
 
        ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
-       if (ret)
-               return ret;
-
+out:
        /*
         * Clear the scan status so the next scan requests will succeed. This
         * also ensures the Rx handler doesn't do anything, as the scan was
@@ -1167,7 +1167,6 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_OS)
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
 
-out:
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 
        if (notify) {
@@ -1177,7 +1176,7 @@ out:
                        ieee80211_scan_completed(mvm->hw, true);
        }
 
-       return 0;
+       return ret;
 }
 
 static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
index 54fafbf..4b81c0b 100644 (file)
@@ -197,6 +197,8 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm,
                             struct iwl_time_event_notif *notif)
 {
        if (!le32_to_cpu(notif->status)) {
+               if (te_data->vif->type == NL80211_IFTYPE_STATION)
+                       ieee80211_connection_loss(te_data->vif);
                IWL_DEBUG_TE(mvm, "CSA time event failed to start\n");
                iwl_mvm_te_clear_data(mvm, te_data);
                return;
@@ -750,8 +752,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
         * request
         */
        list_for_each_entry(te_data, &mvm->time_event_list, list) {
-               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE &&
-                   te_data->running) {
+               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
                        mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
                        is_p2p = true;
                        goto remove_te;
@@ -766,10 +767,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
         * request
         */
        list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
-               if (te_data->running) {
-                       mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
-                       goto remove_te;
-               }
+               mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+               goto remove_te;
        }
 
 remove_te:
index 07304e1..96a0540 100644 (file)
@@ -949,8 +949,10 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        mvmsta = iwl_mvm_sta_from_mac80211(sta);
        tid_data = &mvmsta->tid_data[tid];
 
-       if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d",
-                     tid_data->txq_id, tid, scd_flow)) {
+       if (tid_data->txq_id != scd_flow) {
+               IWL_ERR(mvm,
+                       "invalid BA notification: Q %d, tid %d, flow %d\n",
+                       tid_data->txq_id, tid, scd_flow);
                rcu_read_unlock();
                return 0;
        }
index dbd6bcf..686dd30 100644 (file)
@@ -368,10 +368,12 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
 /* 3165 Series */
        {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3166, 0x4310, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3166, 0x4210, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x8010, iwl3165_2ac_cfg)},
 
 /* 7265 Series */
        {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
index 4a4c658..8908be6 100644 (file)
@@ -946,7 +946,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
                goto nla_put_failure;
 
        genlmsg_end(skb, msg_head);
-       genlmsg_unicast(&init_net, skb, dst_portid);
+       if (genlmsg_unicast(&init_net, skb, dst_portid))
+               goto err_free_txskb;
 
        /* Enqueue the packet */
        skb_queue_tail(&data->pending, my_skb);
@@ -955,6 +956,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        return;
 
 nla_put_failure:
+       nlmsg_free(skb);
+err_free_txskb:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
        ieee80211_free_txskb(hw, my_skb);
        data->tx_failed++;
index 1d46774..074f716 100644 (file)
@@ -1386,8 +1386,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
                }
 
                return true;
-       } else if (0x86DD == ether_type) {
-               return true;
+       } else if (ETH_P_IPV6 == ether_type) {
+               /* TODO: Handle any IPv6 cases that need special handling.
+                * For now, always return false
+                */
+               goto end;
        }
 
 end:
index a62170e..8c45cf4 100644 (file)
@@ -1124,12 +1124,22 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        /*This is for new trx flow*/
        struct rtl_tx_buffer_desc *pbuffer_desc = NULL;
        u8 temp_one = 1;
+       u8 *entry;
 
        memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
        ring = &rtlpci->tx_ring[BEACON_QUEUE];
        pskb = __skb_dequeue(&ring->queue);
-       if (pskb)
+       if (rtlpriv->use_new_trx_flow)
+               entry = (u8 *)(&ring->buffer_desc[ring->idx]);
+       else
+               entry = (u8 *)(&ring->desc[ring->idx]);
+       if (pskb) {
+               pci_unmap_single(rtlpci->pdev,
+                                rtlpriv->cfg->ops->get_desc(
+                                (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+                                pskb->len, PCI_DMA_TODEVICE);
                kfree_skb(pskb);
+       }
 
        /*NB: the beacon data buffer must be 32-bit aligned. */
        pskb = ieee80211_beacon_get(hw, mac->vif);
index f38227a..3aa8648 100644 (file)
@@ -340,12 +340,11 @@ static void xenvif_get_ethtool_stats(struct net_device *dev,
        unsigned int num_queues = vif->num_queues;
        int i;
        unsigned int queue_index;
-       struct xenvif_stats *vif_stats;
 
        for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) {
                unsigned long accum = 0;
                for (queue_index = 0; queue_index < num_queues; ++queue_index) {
-                       vif_stats = &vif->queues[queue_index].stats;
+                       void *vif_stats = &vif->queues[queue_index].stats;
                        accum += *(unsigned long *)(vif_stats + xenvif_stats[i].offset);
                }
                data[i] = accum;
index f7a31d2..997cf09 100644 (file)
@@ -96,6 +96,7 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 static void make_tx_response(struct xenvif_queue *queue,
                             struct xen_netif_tx_request *txp,
                             s8       st);
+static void push_tx_responses(struct xenvif_queue *queue);
 
 static inline int tx_work_todo(struct xenvif_queue *queue);
 
@@ -657,6 +658,7 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
        do {
                spin_lock_irqsave(&queue->response_lock, flags);
                make_tx_response(queue, txp, XEN_NETIF_RSP_ERROR);
+               push_tx_responses(queue);
                spin_unlock_irqrestore(&queue->response_lock, flags);
                if (cons == end)
                        break;
@@ -1343,7 +1345,7 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s
 {
        unsigned int offset = skb_headlen(skb);
        skb_frag_t frags[MAX_SKB_FRAGS];
-       int i;
+       int i, f;
        struct ubuf_info *uarg;
        struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
 
@@ -1383,23 +1385,25 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s
                frags[i].page_offset = 0;
                skb_frag_size_set(&frags[i], len);
        }
-       /* swap out with old one */
-       memcpy(skb_shinfo(skb)->frags,
-              frags,
-              i * sizeof(skb_frag_t));
-       skb_shinfo(skb)->nr_frags = i;
-       skb->truesize += i * PAGE_SIZE;
 
-       /* remove traces of mapped pages and frag_list */
+       /* Copied all the bits from the frag list -- free it. */
        skb_frag_list_init(skb);
+       xenvif_skb_zerocopy_prepare(queue, nskb);
+       kfree_skb(nskb);
+
+       /* Release all the original (foreign) frags. */
+       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+               skb_frag_unref(skb, f);
        uarg = skb_shinfo(skb)->destructor_arg;
        /* increase inflight counter to offset decrement in callback */
        atomic_inc(&queue->inflight_packets);
        uarg->callback(uarg, true);
        skb_shinfo(skb)->destructor_arg = NULL;
 
-       xenvif_skb_zerocopy_prepare(queue, nskb);
-       kfree_skb(nskb);
+       /* Fill the skb with the new (local) frags. */
+       memcpy(skb_shinfo(skb)->frags, frags, i * sizeof(skb_frag_t));
+       skb_shinfo(skb)->nr_frags = i;
+       skb->truesize += i * PAGE_SIZE;
 
        return 0;
 }
@@ -1652,13 +1656,20 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
        unsigned long flags;
 
        pending_tx_info = &queue->pending_tx_info[pending_idx];
+
        spin_lock_irqsave(&queue->response_lock, flags);
+
        make_tx_response(queue, &pending_tx_info->req, status);
-       index = pending_index(queue->pending_prod);
+
+       /* Release the pending index before pusing the Tx response so
+        * its available before a new Tx request is pushed by the
+        * frontend.
+        */
+       index = pending_index(queue->pending_prod++);
        queue->pending_ring[index] = pending_idx;
-       /* TX shouldn't use the index before we give it back here */
-       mb();
-       queue->pending_prod++;
+
+       push_tx_responses(queue);
+
        spin_unlock_irqrestore(&queue->response_lock, flags);
 }
 
@@ -1669,7 +1680,6 @@ static void make_tx_response(struct xenvif_queue *queue,
 {
        RING_IDX i = queue->tx.rsp_prod_pvt;
        struct xen_netif_tx_response *resp;
-       int notify;
 
        resp = RING_GET_RESPONSE(&queue->tx, i);
        resp->id     = txp->id;
@@ -1679,6 +1689,12 @@ static void make_tx_response(struct xenvif_queue *queue,
                RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
 
        queue->tx.rsp_prod_pvt = ++i;
+}
+
+static void push_tx_responses(struct xenvif_queue *queue)
+{
+       int notify;
+
        RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
        if (notify)
                notify_remote_via_irq(queue->tx_irq);
index e9b960f..720aaf6 100644 (file)
@@ -1008,8 +1008,7 @@ err:
 
 static int xennet_change_mtu(struct net_device *dev, int mtu)
 {
-       int max = xennet_can_sg(dev) ?
-               XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER : ETH_DATA_LEN;
+       int max = xennet_can_sg(dev) ? XEN_NETIF_MAX_TX_SIZE : ETH_DATA_LEN;
 
        if (mtu > max)
                return -EINVAL;
@@ -1279,8 +1278,6 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
        netdev->ethtool_ops = &xennet_ethtool_ops;
        SET_NETDEV_DEV(netdev, &dev->dev);
 
-       netif_set_gso_max_size(netdev, XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER);
-
        np->netdev = netdev;
 
        netif_carrier_off(netdev);
index 38d1c51..7bcaeec 100644 (file)
@@ -84,8 +84,7 @@ config OF_RESOLVE
        bool
 
 config OF_OVERLAY
-       bool
-       depends on OF
+       bool "Device Tree overlays"
        select OF_DYNAMIC
        select OF_RESOLVE
 
index ad29069..78a7dcb 100644 (file)
@@ -450,12 +450,17 @@ static struct of_bus *of_match_bus(struct device_node *np)
        return NULL;
 }
 
-static int of_empty_ranges_quirk(void)
+static int of_empty_ranges_quirk(struct device_node *np)
 {
        if (IS_ENABLED(CONFIG_PPC)) {
-               /* To save cycles, we cache the result */
+               /* To save cycles, we cache the result for global "Mac" setting */
                static int quirk_state = -1;
 
+               /* PA-SEMI sdc DT bug */
+               if (of_device_is_compatible(np, "1682m-sdc"))
+                       return true;
+
+               /* Make quirk cached */
                if (quirk_state < 0)
                        quirk_state =
                                of_machine_is_compatible("Power Macintosh") ||
@@ -490,7 +495,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
         * This code is only enabled on powerpc. --gcl
         */
        ranges = of_get_property(parent, rprop, &rlen);
-       if (ranges == NULL && !of_empty_ranges_quirk()) {
+       if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
                pr_debug("OF: no ranges; cannot translate\n");
                return 1;
        }
index 0a8aeb8..8f165b1 100644 (file)
@@ -714,16 +714,12 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
                                                const char *path)
 {
        struct device_node *child;
-       int len = strchrnul(path, '/') - path;
-       int term;
+       int len;
 
+       len = strcspn(path, "/:");
        if (!len)
                return NULL;
 
-       term = strchrnul(path, ':') - path;
-       if (term < len)
-               len = term;
-
        __for_each_child_of_node(parent, child) {
                const char *name = strrchr(child->full_name, '/');
                if (WARN(!name, "malformed device_node %s\n", child->full_name))
@@ -768,8 +764,12 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
 
        /* The path could begin with an alias */
        if (*path != '/') {
-               char *p = strchrnul(path, '/');
-               int len = separator ? separator - path : p - path;
+               int len;
+               const char *p = separator;
+
+               if (!p)
+                       p = strchrnul(path, '/');
+               len = p - path;
 
                /* of_aliases must not be NULL */
                if (!of_aliases)
@@ -794,6 +794,8 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
                path++; /* Increment past '/' delimiter */
                np = __of_find_node_by_path(np, path);
                path = strchrnul(path, '/');
+               if (separator && separator < path)
+                       break;
        }
        raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
index 0d77658..1a79806 100644 (file)
@@ -290,7 +290,7 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
        struct device_node *p;
        const __be32 *intspec, *tmp, *addr;
        u32 intsize, intlen;
-       int i, res = -EINVAL;
+       int i, res;
 
        pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
 
@@ -323,15 +323,19 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
 
        /* Get size of interrupt specifier */
        tmp = of_get_property(p, "#interrupt-cells", NULL);
-       if (tmp == NULL)
+       if (tmp == NULL) {
+               res = -EINVAL;
                goto out;
+       }
        intsize = be32_to_cpu(*tmp);
 
        pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
 
        /* Check index */
-       if ((index + 1) * intsize > intlen)
+       if ((index + 1) * intsize > intlen) {
+               res = -EINVAL;
                goto out;
+       }
 
        /* Copy intspec into irq structure */
        intspec += index * intsize;
index 352b4f2..dee9270 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/idr.h>
 
 #include "of_private.h"
 
@@ -85,7 +86,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
                struct device_node *target, struct device_node *child)
 {
        const char *cname;
-       struct device_node *tchild, *grandchild;
+       struct device_node *tchild;
        int ret = 0;
 
        cname = kbasename(child->full_name);
index 0cf9a23..52c45c7 100644 (file)
@@ -92,6 +92,16 @@ static void __init of_selftest_find_node_by_name(void)
                 "option path test failed\n");
        of_node_put(np);
 
+       np = of_find_node_opts_by_path("/testcase-data:test/option", &options);
+       selftest(np && !strcmp("test/option", options),
+                "option path test, subcase #1 failed\n");
+       of_node_put(np);
+
+       np = of_find_node_opts_by_path("/testcase-data/testcase-device1:test/option", &options);
+       selftest(np && !strcmp("test/option", options),
+                "option path test, subcase #2 failed\n");
+       of_node_put(np);
+
        np = of_find_node_opts_by_path("/testcase-data:testoption", NULL);
        selftest(np, "NULL option path test failed\n");
        of_node_put(np);
@@ -102,6 +112,12 @@ static void __init of_selftest_find_node_by_name(void)
                 "option alias path test failed\n");
        of_node_put(np);
 
+       np = of_find_node_opts_by_path("testcase-alias:test/alias/option",
+                                      &options);
+       selftest(np && !strcmp("test/alias/option", options),
+                "option alias path test, subcase #1 failed\n");
+       of_node_put(np);
+
        np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL);
        selftest(np, "NULL option alias path test failed\n");
        of_node_put(np);
@@ -378,9 +394,9 @@ static void __init of_selftest_property_string(void)
        rc = of_property_match_string(np, "phandle-list-names", "first");
        selftest(rc == 0, "first expected:0 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "second");
-       selftest(rc == 1, "second expected:0 got:%i\n", rc);
+       selftest(rc == 1, "second expected:1 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "third");
-       selftest(rc == 2, "third expected:0 got:%i\n", rc);
+       selftest(rc == 2, "third expected:2 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "fourth");
        selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
        rc = of_property_match_string(np, "missing-property", "blah");
@@ -478,7 +494,6 @@ static void __init of_selftest_changeset(void)
        struct device_node *n1, *n2, *n21, *nremove, *parent, *np;
        struct of_changeset chgset;
 
-       of_changeset_init(&chgset);
        n1 = __of_node_dup(NULL, "/testcase-data/changeset/n1");
        selftest(n1, "testcase setup failure\n");
        n2 = __of_node_dup(NULL, "/testcase-data/changeset/n2");
@@ -979,7 +994,7 @@ static int of_path_platform_device_exists(const char *path)
        return pdev != NULL;
 }
 
-#if IS_ENABLED(CONFIG_I2C)
+#if IS_BUILTIN(CONFIG_I2C)
 
 /* get the i2c client device instantiated at the path */
 static struct i2c_client *of_path_to_i2c_client(const char *path)
@@ -1445,7 +1460,7 @@ static void of_selftest_overlay_11(void)
                return;
 }
 
-#if IS_ENABLED(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
+#if IS_BUILTIN(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
 
 struct selftest_i2c_bus_data {
        struct platform_device  *pdev;
@@ -1584,7 +1599,7 @@ static struct i2c_driver selftest_i2c_dev_driver = {
        .id_table = selftest_i2c_dev_id,
 };
 
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
 
 struct selftest_i2c_mux_data {
        int nchans;
@@ -1695,7 +1710,7 @@ static int of_selftest_overlay_i2c_init(void)
                        "could not register selftest i2c bus driver\n"))
                return ret;
 
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
        ret = i2c_add_driver(&selftest_i2c_mux_driver);
        if (selftest(ret == 0,
                        "could not register selftest i2c mux driver\n"))
@@ -1707,7 +1722,7 @@ static int of_selftest_overlay_i2c_init(void)
 
 static void of_selftest_overlay_i2c_cleanup(void)
 {
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
        i2c_del_driver(&selftest_i2c_mux_driver);
 #endif
        platform_driver_unregister(&selftest_i2c_bus_driver);
@@ -1814,7 +1829,7 @@ static void __init of_selftest_overlay(void)
        of_selftest_overlay_10();
        of_selftest_overlay_11();
 
-#if IS_ENABLED(CONFIG_I2C)
+#if IS_BUILTIN(CONFIG_I2C)
        if (selftest(of_selftest_overlay_i2c_init() == 0, "i2c init failed\n"))
                goto out;
 
index 1ec694a..464bf49 100644 (file)
@@ -80,7 +80,7 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
        if (err)
                return err;
 
-       resource_list_for_each_entry(win, res, list) {
+       resource_list_for_each_entry(win, res) {
                struct resource *parent, *res = win->res;
 
                switch (resource_type(res)) {
index aab5547..ee082c0 100644 (file)
@@ -127,7 +127,7 @@ static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
        return false;
 }
 
-static int xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
                              int offset)
 {
        struct xgene_pcie_port *port = bus->sysdata;
@@ -137,7 +137,7 @@ static int xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
                return NULL;
 
        xgene_pcie_set_rtdid_reg(bus, devfn);
-       return xgene_pcie_get_cfg_base(bus);
+       return xgene_pcie_get_cfg_base(bus) + offset;
 }
 
 static struct pci_ops xgene_pcie_ops = {
index aa012fb..312f23a 100644 (file)
@@ -521,7 +521,8 @@ static ssize_t driver_override_store(struct device *dev,
        struct pci_dev *pdev = to_pci_dev(dev);
        char *driver_override, *old = pdev->driver_override, *cp;
 
-       if (count > PATH_MAX)
+       /* We need to keep extra room for a newline */
+       if (count >= (PAGE_SIZE - 1))
                return -EINVAL;
 
        driver_override = kstrndup(buf, count, GFP_KERNEL);
@@ -549,7 +550,7 @@ static ssize_t driver_override_show(struct device *dev,
 {
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       return sprintf(buf, "%s\n", pdev->driver_override);
+       return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
 }
 static DEVICE_ATTR_RW(driver_override);
 
index 3bb4925..45f67c6 100644 (file)
@@ -69,8 +69,7 @@ config YENTA
        tristate "CardBus yenta-compatible bridge support"
        depends on PCI
        select CARDBUS if !EXPERT
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC if PCMCIA != n
        ---help---
          This option enables support for CardBus host bridges.  Virtually
          all modern PCMCIA bridges are CardBus compatible.  A "bridge" is
@@ -110,8 +109,7 @@ config YENTA_TOSHIBA
 config PD6729
        tristate "Cirrus PD6729 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC
        help
          This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
          device, found in some older laptops and PCMCIA card readers.
@@ -119,8 +117,7 @@ config PD6729
 config I82092
        tristate "i82092 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC
        help
          This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
          found in some older laptops and more commonly in evaluation boards for the
@@ -291,9 +288,6 @@ config ELECTRA_CF
          Say Y here to support the CompactFlash controller on the
          PA Semi Electra eval board.
 
-config PCCARD_PCI
-       bool
-
 config PCCARD_NONSTATIC
        bool
 
index f1a7ca0..27e94b3 100644 (file)
@@ -12,7 +12,6 @@ obj-$(CONFIG_PCMCIA)                          += pcmcia.o
 pcmcia_rsrc-y                                  += rsrc_mgr.o
 pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC)         += rsrc_nonstatic.o
 pcmcia_rsrc-$(CONFIG_PCCARD_IODYN)             += rsrc_iodyn.o
-pcmcia_rsrc-$(CONFIG_PCCARD_PCI)               += rsrc_pci.o
 obj-$(CONFIG_PCCARD)                           += pcmcia_rsrc.o
 
 
diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c
deleted file mode 100644 (file)
index 1f67b3b..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include "cs_internal.h"
-
-
-struct pcmcia_align_data {
-       unsigned long   mask;
-       unsigned long   offset;
-};
-
-static resource_size_t pcmcia_align(void *align_data,
-                               const struct resource *res,
-                               resource_size_t size, resource_size_t align)
-{
-       struct pcmcia_align_data *data = align_data;
-       resource_size_t start;
-
-       start = (res->start & ~data->mask) + data->offset;
-       if (start < res->start)
-               start += data->mask + 1;
-       return start;
-}
-
-static struct resource *find_io_region(struct pcmcia_socket *s,
-                                       unsigned long base, int num,
-                                       unsigned long align)
-{
-       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
-                                               dev_name(&s->dev));
-       struct pcmcia_align_data data;
-       int ret;
-
-       data.mask = align - 1;
-       data.offset = base & data.mask;
-
-       ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
-                                            base, 0, pcmcia_align, &data);
-       if (ret != 0) {
-               kfree(res);
-               res = NULL;
-       }
-       return res;
-}
-
-static int res_pci_find_io(struct pcmcia_socket *s, unsigned int attr,
-                       unsigned int *base, unsigned int num,
-                       unsigned int align, struct resource **parent)
-{
-       int i, ret = 0;
-
-       /* Check for an already-allocated window that must conflict with
-        * what was asked for.  It is a hack because it does not catch all
-        * potential conflicts, just the most obvious ones.
-        */
-       for (i = 0; i < MAX_IO_WIN; i++) {
-               if (!s->io[i].res)
-                       continue;
-
-               if (!*base)
-                       continue;
-
-               if ((s->io[i].res->start & (align-1)) == *base)
-                       return -EBUSY;
-       }
-
-       for (i = 0; i < MAX_IO_WIN; i++) {
-               struct resource *res = s->io[i].res;
-               unsigned int try;
-
-               if (res && (res->flags & IORESOURCE_BITS) !=
-                       (attr & IORESOURCE_BITS))
-                       continue;
-
-               if (!res) {
-                       if (align == 0)
-                               align = 0x10000;
-
-                       res = s->io[i].res = find_io_region(s, *base, num,
-                                                               align);
-                       if (!res)
-                               return -EINVAL;
-
-                       *base = res->start;
-                       s->io[i].res->flags =
-                               ((res->flags & ~IORESOURCE_BITS) |
-                                       (attr & IORESOURCE_BITS));
-                       s->io[i].InUse = num;
-                       *parent = res;
-                       return 0;
-               }
-
-               /* Try to extend top of window */
-               try = res->end + 1;
-               if ((*base == 0) || (*base == try)) {
-                       ret = adjust_resource(s->io[i].res, res->start,
-                                             resource_size(res) + num);
-                       if (ret)
-                               continue;
-                       *base = try;
-                       s->io[i].InUse += num;
-                       *parent = res;
-                       return 0;
-               }
-
-               /* Try to extend bottom of window */
-               try = res->start - num;
-               if ((*base == 0) || (*base == try)) {
-                       ret = adjust_resource(s->io[i].res,
-                                             res->start - num,
-                                             resource_size(res) + num);
-                       if (ret)
-                               continue;
-                       *base = try;
-                       s->io[i].InUse += num;
-                       *parent = res;
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static struct resource *res_pci_find_mem(u_long base, u_long num,
-               u_long align, int low, struct pcmcia_socket *s)
-{
-       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
-                                               dev_name(&s->dev));
-       struct pcmcia_align_data data;
-       unsigned long min;
-       int ret;
-
-       if (align < 0x20000)
-               align = 0x20000;
-       data.mask = align - 1;
-       data.offset = base & data.mask;
-
-       min = 0;
-       if (!low)
-               min = 0x100000UL;
-
-       ret = pci_bus_alloc_resource(s->cb_dev->bus,
-                       res, num, 1, min, 0,
-                       pcmcia_align, &data);
-
-       if (ret != 0) {
-               kfree(res);
-               res = NULL;
-       }
-       return res;
-}
-
-
-static int res_pci_init(struct pcmcia_socket *s)
-{
-       if (!s->cb_dev || !(s->features & SS_CAP_PAGE_REGS)) {
-               dev_err(&s->dev, "not supported by res_pci\n");
-               return -EOPNOTSUPP;
-       }
-       return 0;
-}
-
-struct pccard_resource_ops pccard_nonstatic_ops = {
-       .validate_mem = NULL,
-       .find_io = res_pci_find_io,
-       .find_mem = res_pci_find_mem,
-       .init = res_pci_init,
-       .exit = NULL,
-};
-EXPORT_SYMBOL(pccard_nonstatic_ops);
index 7c99ca2..8ccc395 100644 (file)
@@ -37,7 +37,7 @@ static int armada375_usb_phy_init(struct phy *phy)
        struct armada375_cluster_phy *cluster_phy;
        u32 reg;
 
-       cluster_phy = dev_get_drvdata(phy->dev.parent);
+       cluster_phy = phy_get_drvdata(phy);
        if (!cluster_phy)
                return -ENODEV;
 
@@ -131,6 +131,7 @@ static int armada375_usb_phy_probe(struct platform_device *pdev)
        cluster_phy->reg = usb_cluster_base;
 
        dev_set_drvdata(dev, cluster_phy);
+       phy_set_drvdata(phy, cluster_phy);
 
        phy_provider = devm_of_phy_provider_register(&pdev->dev,
                                                     armada375_usb_phy_xlate);
index a12d353..3791838 100644 (file)
@@ -52,7 +52,9 @@ static void devm_phy_consume(struct device *dev, void *res)
 
 static int devm_phy_match(struct device *dev, void *res, void *match_data)
 {
-       return res == match_data;
+       struct phy **phy = res;
+
+       return *phy == match_data;
 }
 
 /**
@@ -223,6 +225,7 @@ int phy_init(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->init_count == 0 && phy->ops->init) {
@@ -231,8 +234,6 @@ int phy_init(struct phy *phy)
                        dev_err(&phy->dev, "phy init failed --> %d\n", ret);
                        goto out;
                }
-       } else {
-               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->init_count;
 
@@ -253,6 +254,7 @@ int phy_exit(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->init_count == 1 && phy->ops->exit) {
@@ -287,6 +289,7 @@ int phy_power_on(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->power_count == 0 && phy->ops->power_on) {
@@ -295,8 +298,6 @@ int phy_power_on(struct phy *phy)
                        dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
                        goto out;
                }
-       } else {
-               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->power_count;
        mutex_unlock(&phy->mutex);
index f86cbe6..179cbf9 100644 (file)
@@ -30,28 +30,13 @@ struct exynos_dp_video_phy {
        const struct exynos_dp_video_phy_drvdata *drvdata;
 };
 
-static void exynos_dp_video_phy_pwr_isol(struct exynos_dp_video_phy *state,
-                                                       unsigned int on)
-{
-       unsigned int val;
-
-       if (IS_ERR(state->regs))
-               return;
-
-       val = on ? 0 : EXYNOS5_PHY_ENABLE;
-
-       regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
-                          EXYNOS5_PHY_ENABLE, val);
-}
-
 static int exynos_dp_video_phy_power_on(struct phy *phy)
 {
        struct exynos_dp_video_phy *state = phy_get_drvdata(phy);
 
        /* Disable power isolation on DP-PHY */
-       exynos_dp_video_phy_pwr_isol(state, 0);
-
-       return 0;
+       return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
+                                 EXYNOS5_PHY_ENABLE, EXYNOS5_PHY_ENABLE);
 }
 
 static int exynos_dp_video_phy_power_off(struct phy *phy)
@@ -59,9 +44,8 @@ static int exynos_dp_video_phy_power_off(struct phy *phy)
        struct exynos_dp_video_phy *state = phy_get_drvdata(phy);
 
        /* Enable power isolation on DP-PHY */
-       exynos_dp_video_phy_pwr_isol(state, 1);
-
-       return 0;
+       return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
+                                 EXYNOS5_PHY_ENABLE, 0);
 }
 
 static struct phy_ops exynos_dp_video_phy_ops = {
index f017b2f..df7519a 100644 (file)
@@ -43,7 +43,6 @@ struct exynos_mipi_video_phy {
        } phys[EXYNOS_MIPI_PHYS_NUM];
        spinlock_t slock;
        void __iomem *regs;
-       struct mutex mutex;
        struct regmap *regmap;
 };
 
@@ -59,8 +58,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
        else
                reset = EXYNOS4_MIPI_PHY_SRESETN;
 
-       if (state->regmap) {
-               mutex_lock(&state->mutex);
+       spin_lock(&state->slock);
+
+       if (!IS_ERR(state->regmap)) {
                regmap_read(state->regmap, offset, &val);
                if (on)
                        val |= reset;
@@ -72,11 +72,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
                else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
                        val &= ~EXYNOS4_MIPI_PHY_ENABLE;
                regmap_write(state->regmap, offset, val);
-               mutex_unlock(&state->mutex);
        } else {
                addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
 
-               spin_lock(&state->slock);
                val = readl(addr);
                if (on)
                        val |= reset;
@@ -90,9 +88,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
                        val &= ~EXYNOS4_MIPI_PHY_ENABLE;
 
                writel(val, addr);
-               spin_unlock(&state->slock);
        }
 
+       spin_unlock(&state->slock);
        return 0;
 }
 
@@ -158,7 +156,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
 
        dev_set_drvdata(dev, state);
        spin_lock_init(&state->slock);
-       mutex_init(&state->mutex);
 
        for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
                struct phy *phy = devm_phy_create(dev, NULL,
index 236a52a..f30bbb0 100644 (file)
@@ -250,7 +250,6 @@ static const struct samsung_usb2_common_phy exynos4210_phys[] = {
                .power_on       = exynos4210_power_on,
                .power_off      = exynos4210_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
index 0b9de88..765da90 100644 (file)
@@ -361,7 +361,6 @@ static const struct samsung_usb2_common_phy exynos4x12_phys[] = {
                .power_on       = exynos4x12_power_on,
                .power_off      = exynos4x12_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos3250_usb2_phy_config = {
index 0437401..e2a0be7 100644 (file)
@@ -531,7 +531,7 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
 {
        struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
 
-       if (WARN_ON(args->args[0] > EXYNOS5_DRDPHYS_NUM))
+       if (WARN_ON(args->args[0] >= EXYNOS5_DRDPHYS_NUM))
                return ERR_PTR(-ENODEV);
 
        return phy_drd->phys[args->args[0]].phy;
index 1c139aa..2ed1735 100644 (file)
@@ -391,7 +391,6 @@ static const struct samsung_usb2_common_phy exynos5250_phys[] = {
                .power_on       = exynos5250_power_on,
                .power_off      = exynos5250_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
index 34915b4..d6b2265 100644 (file)
@@ -147,6 +147,9 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
        priv->base = devm_ioremap(dev, res->start, resource_size(res));
        if (!priv->base)
                return -ENOMEM;
index 9b2848e..9334352 100644 (file)
@@ -228,6 +228,7 @@ struct miphy28lp_dev {
        struct regmap *regmap;
        struct mutex miphy_mutex;
        struct miphy28lp_phy **phys;
+       int nphys;
 };
 
 struct miphy_initval {
@@ -1116,7 +1117,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       for (index = 0; index < of_get_child_count(dev->of_node); index++)
+       for (index = 0; index < miphy_dev->nphys; index++)
                if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
                        miphy_phy = miphy_dev->phys[index];
                        break;
@@ -1138,6 +1139,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
 
 static struct phy_ops miphy28lp_ops = {
        .init = miphy28lp_init,
+       .owner = THIS_MODULE,
 };
 
 static int miphy28lp_probe_resets(struct device_node *node,
@@ -1200,16 +1202,15 @@ static int miphy28lp_probe(struct platform_device *pdev)
        struct miphy28lp_dev *miphy_dev;
        struct phy_provider *provider;
        struct phy *phy;
-       int chancount, port = 0;
-       int ret;
+       int ret, port = 0;
 
        miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
        if (!miphy_dev)
                return -ENOMEM;
 
-       chancount = of_get_child_count(np);
-       miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
-                                      GFP_KERNEL);
+       miphy_dev->nphys = of_get_child_count(np);
+       miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
+                                      sizeof(*miphy_dev->phys), GFP_KERNEL);
        if (!miphy_dev->phys)
                return -ENOMEM;
 
index 6c80154..51b459d 100644 (file)
@@ -150,6 +150,7 @@ struct miphy365x_dev {
        struct regmap *regmap;
        struct mutex miphy_mutex;
        struct miphy365x_phy **phys;
+       int nphys;
 };
 
 /*
@@ -485,7 +486,7 @@ static struct phy *miphy365x_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       for (index = 0; index < of_get_child_count(dev->of_node); index++)
+       for (index = 0; index < miphy_dev->nphys; index++)
                if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
                        miphy_phy = miphy_dev->phys[index];
                        break;
@@ -541,16 +542,15 @@ static int miphy365x_probe(struct platform_device *pdev)
        struct miphy365x_dev *miphy_dev;
        struct phy_provider *provider;
        struct phy *phy;
-       int chancount, port = 0;
-       int ret;
+       int ret, port = 0;
 
        miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
        if (!miphy_dev)
                return -ENOMEM;
 
-       chancount = of_get_child_count(np);
-       miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
-                                      GFP_KERNEL);
+       miphy_dev->nphys = of_get_child_count(np);
+       miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
+                                      sizeof(*miphy_dev->phys), GFP_KERNEL);
        if (!miphy_dev->phys)
                return -ENOMEM;
 
index efe724f..93252e0 100644 (file)
@@ -360,7 +360,7 @@ static void __exit omap_control_phy_exit(void)
 }
 module_exit(omap_control_phy_exit);
 
-MODULE_ALIAS("platform: omap_control_phy");
+MODULE_ALIAS("platform:omap_control_phy");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP Control Module PHY Driver");
 MODULE_LICENSE("GPL v2");
index 6f4aef3..4757e76 100644 (file)
@@ -296,10 +296,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
                        dev_warn(&pdev->dev,
                                 "found usb_otg_ss_refclk960m, please fix DTS\n");
                }
-       } else {
-               clk_prepare(phy->optclk);
        }
 
+       if (!IS_ERR(phy->optclk))
+               clk_prepare(phy->optclk);
+
        usb_add_phy_dev(&phy->phy);
 
        return 0;
@@ -383,7 +384,7 @@ static struct platform_driver omap_usb2_driver = {
 
 module_platform_driver(omap_usb2_driver);
 
-MODULE_ALIAS("platform: omap_usb2");
+MODULE_ALIAS("platform:omap_usb2");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP USB2 phy driver");
 MODULE_LICENSE("GPL v2");
index 22011c3..7d4c336 100644 (file)
@@ -61,8 +61,6 @@ static int rockchip_usb_phy_power_off(struct phy *_phy)
                return ret;
 
        clk_disable_unprepare(phy->clk);
-       if (ret)
-               return ret;
 
        return 0;
 }
@@ -78,8 +76,10 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
 
        /* Power up usb phy analog blocks by set siddq 0 */
        ret = rockchip_usb_phy_power(phy, 0);
-       if (ret)
+       if (ret) {
+               clk_disable_unprepare(phy->clk);
                return ret;
+       }
 
        return 0;
 }
index 95c88f9..2ba610b 100644 (file)
@@ -165,15 +165,11 @@ static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy)
                cpu_relax();
                val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
                if (val & PLL_LOCK)
-                       break;
+                       return 0;
        } while (!time_after(jiffies, timeout));
 
-       if (!(val & PLL_LOCK)) {
-               dev_err(phy->dev, "DPLL failed to lock\n");
-               return -EBUSY;
-       }
-
-       return 0;
+       dev_err(phy->dev, "DPLL failed to lock\n");
+       return -EBUSY;
 }
 
 static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
@@ -608,7 +604,7 @@ static struct platform_driver ti_pipe3_driver = {
 
 module_platform_driver(ti_pipe3_driver);
 
-MODULE_ALIAS("platform: ti_pipe3");
+MODULE_ALIAS("platform:ti_pipe3");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TI PIPE3 phy driver");
 MODULE_LICENSE("GPL v2");
index 8e87f54..bc42d6a 100644 (file)
@@ -666,7 +666,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        twl->dev                = &pdev->dev;
        twl->irq                = platform_get_irq(pdev, 0);
        twl->vbus_supplied      = false;
-       twl->linkstat           = -EINVAL;
        twl->linkstat           = OMAP_MUSB_UNKNOWN;
 
        twl->phy.dev            = twl->dev;
index 29214a3..2263cd0 100644 (file)
@@ -1704,7 +1704,6 @@ static int xgene_phy_probe(struct platform_device *pdev)
        for (i = 0; i < MAX_LANE; i++)
                ctx->sata_param.speed[i] = 2; /* Default to Gen3 */
 
-       ctx->dev = &pdev->dev;
        platform_set_drvdata(pdev, ctx);
 
        ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops);
index 5afe03e..2062c22 100644 (file)
 #define BYT_DIR_MASK           (BIT(1) | BIT(2))
 #define BYT_TRIG_MASK          (BIT(26) | BIT(25) | BIT(24))
 
+#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | \
+                                BYT_PIN_MUX)
+#define BYT_VAL_RESTORE_MASK   (BYT_DIR_MASK | BYT_LEVEL)
+
 #define BYT_NGPIO_SCORE                102
 #define BYT_NGPIO_NCORE                28
 #define BYT_NGPIO_SUS          44
@@ -134,12 +138,18 @@ static struct pinctrl_gpio_range byt_ranges[] = {
        },
 };
 
+struct byt_gpio_pin_context {
+       u32 conf0;
+       u32 val;
+};
+
 struct byt_gpio {
        struct gpio_chip                chip;
        struct platform_device          *pdev;
        spinlock_t                      lock;
        void __iomem                    *reg_base;
        struct pinctrl_gpio_range       *range;
+       struct byt_gpio_pin_context     *saved_context;
 };
 
 #define to_byt_gpio(c) container_of(c, struct byt_gpio, chip)
@@ -158,40 +168,62 @@ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
        return vg->reg_base + reg_offset + reg;
 }
 
-static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned offset)
+{
+       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       unsigned long flags;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+       value = readl(reg);
+       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
+       writel(value, reg);
+       spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset)
 {
        /* SCORE pin 92-93 */
        if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
                offset >= 92 && offset <= 93)
-               return true;
+               return 1;
 
        /* SUS pin 11-21 */
        if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
                offset >= 11 && offset <= 21)
-               return true;
+               return 1;
 
-       return false;
+       return 0;
 }
 
 static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
        void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
-       u32 value;
-       bool special;
+       u32 value, gpio_mux;
 
        /*
         * In most cases, func pin mux 000 means GPIO function.
         * But, some pins may have func pin mux 001 represents
-        * GPIO function. Only allow user to export pin with
-        * func pin mux preset as GPIO function by BIOS/FW.
+        * GPIO function.
+        *
+        * Because there are devices out there where some pins were not
+        * configured correctly we allow changing the mux value from
+        * request (but print out warning about that).
         */
        value = readl(reg) & BYT_PIN_MUX;
-       special = is_special_pin(vg, offset);
-       if ((special && value != 1) || (!special && value)) {
-               dev_err(&vg->pdev->dev,
-                       "pin %u cannot be used as GPIO.\n", offset);
-               return -EINVAL;
+       gpio_mux = byt_get_gpio_mux(vg, offset);
+       if (WARN_ON(gpio_mux != value)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&vg->lock, flags);
+               value = readl(reg) & ~BYT_PIN_MUX;
+               value |= gpio_mux;
+               writel(value, reg);
+               spin_unlock_irqrestore(&vg->lock, flags);
+
+               dev_warn(&vg->pdev->dev,
+                        "pin %u forcibly re-configured as GPIO\n", offset);
        }
 
        pm_runtime_get(&vg->pdev->dev);
@@ -202,14 +234,8 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
-       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
-       u32 value;
-
-       /* clear interrupt triggering */
-       value = readl(reg);
-       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
-       writel(value, reg);
 
+       byt_gpio_clear_triggering(vg, offset);
        pm_runtime_put(&vg->pdev->dev);
 }
 
@@ -236,23 +262,13 @@ static int byt_irq_type(struct irq_data *d, unsigned type)
        value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG |
                   BYT_TRIG_LVL);
 
-       switch (type) {
-       case IRQ_TYPE_LEVEL_HIGH:
-               value |= BYT_TRIG_LVL;
-       case IRQ_TYPE_EDGE_RISING:
-               value |= BYT_TRIG_POS;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               value |= BYT_TRIG_LVL;
-       case IRQ_TYPE_EDGE_FALLING:
-               value |= BYT_TRIG_NEG;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
-               break;
-       }
        writel(value, reg);
 
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+       else if (type & IRQ_TYPE_LEVEL_MASK)
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+
        spin_unlock_irqrestore(&vg->lock, flags);
 
        return 0;
@@ -410,58 +426,80 @@ static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
        struct irq_data *data = irq_desc_get_irq_data(desc);
        struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
        struct irq_chip *chip = irq_data_get_irq_chip(data);
-       u32 base, pin, mask;
+       u32 base, pin;
        void __iomem *reg;
-       u32 pending;
+       unsigned long pending;
        unsigned virq;
-       int looplimit = 0;
 
        /* check from GPIO controller which pin triggered the interrupt */
        for (base = 0; base < vg->chip.ngpio; base += 32) {
-
                reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
-
-               while ((pending = readl(reg))) {
-                       pin = __ffs(pending);
-                       mask = BIT(pin);
-                       /* Clear before handling so we can't lose an edge */
-                       writel(mask, reg);
-
+               pending = readl(reg);
+               for_each_set_bit(pin, &pending, 32) {
                        virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
                        generic_handle_irq(virq);
-
-                       /* In case bios or user sets triggering incorretly a pin
-                        * might remain in "interrupt triggered" state.
-                        */
-                       if (looplimit++ > 32) {
-                               dev_err(&vg->pdev->dev,
-                                       "Gpio %d interrupt flood, disabling\n",
-                                       base + pin);
-
-                               reg = byt_gpio_reg(&vg->chip, base + pin,
-                                                  BYT_CONF0_REG);
-                               mask = readl(reg);
-                               mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
-                                         BYT_TRIG_LVL);
-                               writel(mask, reg);
-                               mask = readl(reg); /* flush */
-                               break;
-                       }
                }
        }
        chip->irq_eoi(data);
 }
 
+static void byt_irq_ack(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+       unsigned offset = irqd_to_hwirq(d);
+       void __iomem *reg;
+
+       reg = byt_gpio_reg(&vg->chip, offset, BYT_INT_STAT_REG);
+       writel(BIT(offset % 32), reg);
+}
+
 static void byt_irq_unmask(struct irq_data *d)
 {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+       unsigned offset = irqd_to_hwirq(d);
+       unsigned long flags;
+       void __iomem *reg;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+
+       reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       value = readl(reg);
+
+       switch (irqd_get_trigger_type(d)) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_RISING:
+               value |= BYT_TRIG_POS;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_FALLING:
+               value |= BYT_TRIG_NEG;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
+               break;
+       }
+
+       writel(value, reg);
+
+       spin_unlock_irqrestore(&vg->lock, flags);
 }
 
 static void byt_irq_mask(struct irq_data *d)
 {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+
+       byt_gpio_clear_triggering(vg, irqd_to_hwirq(d));
 }
 
 static struct irq_chip byt_irqchip = {
        .name = "BYT-GPIO",
+       .irq_ack = byt_irq_ack,
        .irq_mask = byt_irq_mask,
        .irq_unmask = byt_irq_unmask,
        .irq_set_type = byt_irq_type,
@@ -472,6 +510,21 @@ static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
 {
        void __iomem *reg;
        u32 base, value;
+       int i;
+
+       /*
+        * Clear interrupt triggers for all pins that are GPIOs and
+        * do not use direct IRQ mode. This will prevent spurious
+        * interrupts from misconfigured pins.
+        */
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               value = readl(byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG));
+               if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i) &&
+                   !(value & BYT_DIRECT_IRQ_EN)) {
+                       byt_gpio_clear_triggering(vg, i);
+                       dev_dbg(&vg->pdev->dev, "disabling GPIO %d\n", i);
+               }
+       }
 
        /* clear interrupt status trigger registers */
        for (base = 0; base < vg->chip.ngpio; base += 32) {
@@ -541,6 +594,11 @@ static int byt_gpio_probe(struct platform_device *pdev)
        gc->can_sleep = false;
        gc->dev = dev;
 
+#ifdef CONFIG_PM_SLEEP
+       vg->saved_context = devm_kcalloc(&pdev->dev, gc->ngpio,
+                                      sizeof(*vg->saved_context), GFP_KERNEL);
+#endif
+
        ret = gpiochip_add(gc);
        if (ret) {
                dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
@@ -569,6 +627,69 @@ static int byt_gpio_probe(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int byt_gpio_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               void __iomem *reg;
+               u32 value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG);
+               value = readl(reg) & BYT_CONF0_RESTORE_MASK;
+               vg->saved_context[i].conf0 = value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG);
+               value = readl(reg) & BYT_VAL_RESTORE_MASK;
+               vg->saved_context[i].val = value;
+       }
+
+       return 0;
+}
+
+static int byt_gpio_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               void __iomem *reg;
+               u32 value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG);
+               value = readl(reg);
+               if ((value & BYT_CONF0_RESTORE_MASK) !=
+                    vg->saved_context[i].conf0) {
+                       value &= ~BYT_CONF0_RESTORE_MASK;
+                       value |= vg->saved_context[i].conf0;
+                       writel(value, reg);
+                       dev_info(dev, "restored pin %d conf0 %#08x", i, value);
+               }
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG);
+               value = readl(reg);
+               if ((value & BYT_VAL_RESTORE_MASK) !=
+                    vg->saved_context[i].val) {
+                       u32 v;
+
+                       v = value & ~BYT_VAL_RESTORE_MASK;
+                       v |= vg->saved_context[i].val;
+                       if (v != value) {
+                               writel(v, reg);
+                               dev_dbg(dev, "restored pin %d val %#08x\n",
+                                       i, v);
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
 static int byt_gpio_runtime_suspend(struct device *dev)
 {
        return 0;
@@ -580,8 +701,9 @@ static int byt_gpio_runtime_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops byt_gpio_pm_ops = {
-       .runtime_suspend = byt_gpio_runtime_suspend,
-       .runtime_resume = byt_gpio_runtime_resume,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(byt_gpio_suspend, byt_gpio_resume)
+       SET_RUNTIME_PM_OPS(byt_gpio_runtime_suspend, byt_gpio_runtime_resume,
+                          NULL)
 };
 
 static const struct acpi_device_id byt_gpio_acpi_match[] = {
index 3034fd0..82f691e 100644 (file)
@@ -1226,6 +1226,7 @@ static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
                                     int value)
 {
+       chv_gpio_set(chip, offset, value);
        return pinctrl_gpio_direction_output(chip->base + offset);
 }
 
index f4cd0b9..a481406 100644 (file)
@@ -1477,28 +1477,25 @@ static void gpio_irq_ack(struct irq_data *d)
        /* the interrupt is already cleared before by reading ISR */
 }
 
-static unsigned int gpio_irq_startup(struct irq_data *d)
+static int gpio_irq_request_res(struct irq_data *d)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
        unsigned        pin = d->hwirq;
        int ret;
 
        ret = gpiochip_lock_as_irq(&at91_gpio->chip, pin);
-       if (ret) {
+       if (ret)
                dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n",
                        d->hwirq);
-               return ret;
-       }
-       gpio_irq_unmask(d);
-       return 0;
+
+       return ret;
 }
 
-static void gpio_irq_shutdown(struct irq_data *d)
+static void gpio_irq_release_res(struct irq_data *d)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
        unsigned        pin = d->hwirq;
 
-       gpio_irq_mask(d);
        gpiochip_unlock_as_irq(&at91_gpio->chip, pin);
 }
 
@@ -1577,8 +1574,8 @@ void at91_pinctrl_gpio_resume(void)
 static struct irq_chip gpio_irqchip = {
        .name           = "GPIO",
        .irq_ack        = gpio_irq_ack,
-       .irq_startup    = gpio_irq_startup,
-       .irq_shutdown   = gpio_irq_shutdown,
+       .irq_request_resources = gpio_irq_request_res,
+       .irq_release_resources = gpio_irq_release_res,
        .irq_disable    = gpio_irq_mask,
        .irq_mask       = gpio_irq_mask,
        .irq_unmask     = gpio_irq_unmask,
index 24c5d88..3c68a8e 100644 (file)
@@ -1011,6 +1011,7 @@ static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
        .pins = sun4i_a10_pins,
        .npins = ARRAY_SIZE(sun4i_a10_pins),
        .irq_banks = 1,
+       .irq_read_needs_mux = true,
 };
 
 static int sun4i_a10_pinctrl_probe(struct platform_device *pdev)
index 3d07443..f8e171b 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 
 #include "../core.h"
+#include "../../gpio/gpiolib.h"
 #include "pinctrl-sunxi.h"
 
 static struct irq_chip sunxi_pinctrl_edge_irq_chip;
@@ -464,10 +465,19 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
 static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
-
        u32 reg = sunxi_data_reg(offset);
        u8 index = sunxi_data_offset(offset);
-       u32 val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+       u32 set_mux = pctl->desc->irq_read_needs_mux &&
+                       test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
+       u32 val;
+
+       if (set_mux)
+               sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_INPUT);
+
+       val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+
+       if (set_mux)
+               sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_IRQ);
 
        return val;
 }
index 5a51523..e248e81 100644 (file)
@@ -77,6 +77,9 @@
 #define IRQ_LEVEL_LOW          0x03
 #define IRQ_EDGE_BOTH          0x04
 
+#define SUN4I_FUNC_INPUT       0
+#define SUN4I_FUNC_IRQ         6
+
 struct sunxi_desc_function {
        const char      *name;
        u8              muxval;
@@ -94,6 +97,7 @@ struct sunxi_pinctrl_desc {
        int                             npins;
        unsigned                        pin_base;
        unsigned                        irq_banks;
+       bool                            irq_read_needs_mux;
 };
 
 struct sunxi_pinctrl_function {
index 97b5e4e..63d4033 100644 (file)
@@ -73,7 +73,7 @@
 
 #define TIME_WINDOW_MAX_MSEC 40000
 #define TIME_WINDOW_MIN_MSEC 250
-
+#define ENERGY_UNIT_SCALE    1000 /* scale from driver unit to powercap unit */
 enum unit_type {
        ARBITRARY_UNIT, /* no translation */
        POWER_UNIT,
@@ -158,6 +158,7 @@ struct rapl_domain {
        struct rapl_power_limit rpl[NR_POWER_LIMITS];
        u64 attr_map; /* track capabilities */
        unsigned int state;
+       unsigned int domain_energy_unit;
        int package_id;
 };
 #define power_zone_to_rapl_domain(_zone) \
@@ -190,6 +191,7 @@ struct rapl_defaults {
        void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
        u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
                                bool to_raw);
+       unsigned int dram_domain_energy_unit;
 };
 static struct rapl_defaults *rapl_defaults;
 
@@ -227,7 +229,8 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 static int rapl_write_data_raw(struct rapl_domain *rd,
                        enum rapl_primitives prim,
                        unsigned long long value);
-static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
+static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+                       enum unit_type type, u64 value,
                        int to_raw);
 static void package_power_limit_irq_save(int package_id);
 
@@ -305,7 +308,9 @@ static int get_energy_counter(struct powercap_zone *power_zone, u64 *energy_raw)
 
 static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy)
 {
-       *energy = rapl_unit_xlate(0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
+       struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev);
+
+       *energy = rapl_unit_xlate(rd, 0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
        return 0;
 }
 
@@ -639,6 +644,11 @@ static void rapl_init_domains(struct rapl_package *rp)
                        rd->msrs[4] = MSR_DRAM_POWER_INFO;
                        rd->rpl[0].prim_id = PL1_ENABLE;
                        rd->rpl[0].name = pl1_name;
+                       rd->domain_energy_unit =
+                               rapl_defaults->dram_domain_energy_unit;
+                       if (rd->domain_energy_unit)
+                               pr_info("DRAM domain energy unit %dpj\n",
+                                       rd->domain_energy_unit);
                        break;
                }
                if (mask) {
@@ -648,11 +658,13 @@ static void rapl_init_domains(struct rapl_package *rp)
        }
 }
 
-static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
+static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+                       enum unit_type type, u64 value,
                        int to_raw)
 {
        u64 units = 1;
        struct rapl_package *rp;
+       u64 scale = 1;
 
        rp = find_package_by_id(package);
        if (!rp)
@@ -663,7 +675,12 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
                units = rp->power_unit;
                break;
        case ENERGY_UNIT:
-               units = rp->energy_unit;
+               scale = ENERGY_UNIT_SCALE;
+               /* per domain unit takes precedence */
+               if (rd && rd->domain_energy_unit)
+                       units = rd->domain_energy_unit;
+               else
+                       units = rp->energy_unit;
                break;
        case TIME_UNIT:
                return rapl_defaults->compute_time_window(rp, value, to_raw);
@@ -673,11 +690,11 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
        };
 
        if (to_raw)
-               return div64_u64(value, units);
+               return div64_u64(value, units) * scale;
 
        value *= units;
 
-       return value;
+       return div64_u64(value, scale);
 }
 
 /* in the order of enum rapl_primitives */
@@ -773,7 +790,7 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
        final = value & rp->mask;
        final = final >> rp->shift;
        if (xlate)
-               *data = rapl_unit_xlate(rd->package_id, rp->unit, final, 0);
+               *data = rapl_unit_xlate(rd, rd->package_id, rp->unit, final, 0);
        else
                *data = final;
 
@@ -799,7 +816,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
                        "failed to read msr 0x%x on cpu %d\n", msr, cpu);
                return -EIO;
        }
-       value = rapl_unit_xlate(rd->package_id, rp->unit, value, 1);
+       value = rapl_unit_xlate(rd, rd->package_id, rp->unit, value, 1);
        msr_val &= ~rp->mask;
        msr_val |= value << rp->shift;
        if (wrmsrl_safe_on_cpu(cpu, msr, msr_val)) {
@@ -818,7 +835,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
  * calculate units differ on different CPUs.
  * We convert the units to below format based on CPUs.
  * i.e.
- * energy unit: microJoules : Represented in microJoules by default
+ * energy unit: picoJoules  : Represented in picoJoules by default
  * power unit : microWatts  : Represented in milliWatts by default
  * time unit  : microseconds: Represented in seconds by default
  */
@@ -834,7 +851,7 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
        }
 
        value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = 1000000 / (1 << value);
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
 
        value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
        rp->power_unit = 1000000 / (1 << value);
@@ -842,7 +859,7 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
        value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
        rp->time_unit = 1000000 / (1 << value);
 
-       pr_debug("Core CPU package %d energy=%duJ, time=%dus, power=%duW\n",
+       pr_debug("Core CPU package %d energy=%dpJ, time=%dus, power=%duW\n",
                rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
 
        return 0;
@@ -859,7 +876,7 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
                return -ENODEV;
        }
        value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = 1 << value;
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
 
        value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
        rp->power_unit = (1 << value) * 1000;
@@ -867,7 +884,7 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
        value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
        rp->time_unit = 1000000 / (1 << value);
 
-       pr_debug("Atom package %d energy=%duJ, time=%dus, power=%duW\n",
+       pr_debug("Atom package %d energy=%dpJ, time=%dus, power=%duW\n",
                rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
 
        return 0;
@@ -1017,6 +1034,13 @@ static const struct rapl_defaults rapl_defaults_core = {
        .compute_time_window = rapl_compute_time_window_core,
 };
 
+static const struct rapl_defaults rapl_defaults_hsw_server = {
+       .check_unit = rapl_check_unit_core,
+       .set_floor_freq = set_floor_freq_default,
+       .compute_time_window = rapl_compute_time_window_core,
+       .dram_domain_energy_unit = 15300,
+};
+
 static const struct rapl_defaults rapl_defaults_atom = {
        .check_unit = rapl_check_unit_atom,
        .set_floor_freq = set_floor_freq_atom,
@@ -1037,7 +1061,7 @@ static const struct x86_cpu_id rapl_ids[] = {
        RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */
        RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */
        RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */
-       RAPL_CPU(0x3f, rapl_defaults_core),/* Haswell */
+       RAPL_CPU(0x3f, rapl_defaults_hsw_server),/* Haswell servers */
        RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */
        RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */
        RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */
index b899947..a4a8a6d 100644 (file)
@@ -1839,10 +1839,12 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
        }
 
        if (rdev->ena_pin) {
-               ret = regulator_ena_gpio_ctrl(rdev, true);
-               if (ret < 0)
-                       return ret;
-               rdev->ena_gpio_state = 1;
+               if (!rdev->ena_gpio_state) {
+                       ret = regulator_ena_gpio_ctrl(rdev, true);
+                       if (ret < 0)
+                               return ret;
+                       rdev->ena_gpio_state = 1;
+               }
        } else if (rdev->desc->ops->enable) {
                ret = rdev->desc->ops->enable(rdev);
                if (ret < 0)
@@ -1939,10 +1941,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
        trace_regulator_disable(rdev_get_name(rdev));
 
        if (rdev->ena_pin) {
-               ret = regulator_ena_gpio_ctrl(rdev, false);
-               if (ret < 0)
-                       return ret;
-               rdev->ena_gpio_state = 0;
+               if (rdev->ena_gpio_state) {
+                       ret = regulator_ena_gpio_ctrl(rdev, false);
+                       if (ret < 0)
+                               return ret;
+                       rdev->ena_gpio_state = 0;
+               }
 
        } else if (rdev->desc->ops->disable) {
                ret = rdev->desc->ops->disable(rdev);
@@ -3444,13 +3448,6 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
        if (attr == &dev_attr_requested_microamps.attr)
                return rdev->desc->type == REGULATOR_CURRENT ? mode : 0;
 
-       /* all the other attributes exist to support constraints;
-        * don't show them if there are no constraints, or if the
-        * relevant supporting methods are missing.
-        */
-       if (!rdev->constraints)
-               return 0;
-
        /* constraints need specific supporting methods */
        if (attr == &dev_attr_min_microvolts.attr ||
            attr == &dev_attr_max_microvolts.attr)
@@ -3633,12 +3630,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
                                 config->ena_gpio, ret);
                        goto wash;
                }
-
-               if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
-                       rdev->ena_gpio_state = 1;
-
-               if (config->ena_gpio_invert)
-                       rdev->ena_gpio_state = !rdev->ena_gpio_state;
        }
 
        /* set regulator constraints */
@@ -3807,9 +3798,11 @@ int regulator_suspend_finish(void)
        list_for_each_entry(rdev, &regulator_list, list) {
                mutex_lock(&rdev->mutex);
                if (rdev->use_count > 0  || rdev->constraints->always_on) {
-                       error = _regulator_do_enable(rdev);
-                       if (error)
-                               ret = error;
+                       if (!_regulator_is_enabled(rdev)) {
+                               error = _regulator_do_enable(rdev);
+                               if (error)
+                                       ret = error;
+                       }
                } else {
                        if (!have_full_constraints())
                                goto unlock;
index bc61001..f0489cb 100644 (file)
@@ -152,6 +152,15 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
        config.regmap = chip->regmap;
        config.of_node = dev->of_node;
 
+       /* Mask all interrupt sources to deassert interrupt line */
+       error = regmap_write(chip->regmap, DA9210_REG_MASK_A, ~0);
+       if (!error)
+               error = regmap_write(chip->regmap, DA9210_REG_MASK_B, ~0);
+       if (error) {
+               dev_err(&i2c->dev, "Failed to write to mask reg: %d\n", error);
+               return error;
+       }
+
        rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config);
        if (IS_ERR(rdev)) {
                dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");
index 9205f43..1819831 100644 (file)
@@ -1572,6 +1572,10 @@ static int palmas_regulators_probe(struct platform_device *pdev)
        if (!pmic)
                return -ENOMEM;
 
+       if (of_device_is_compatible(node, "ti,tps659038-pmic"))
+               palmas_generic_regs_info[PALMAS_REG_REGEN2].ctrl_addr =
+                                                       TPS659038_REGEN2_CTRL;
+
        pmic->dev = &pdev->dev;
        pmic->palmas = palmas;
        palmas->pmic = pmic;
index 1f93b75..3fd4435 100644 (file)
@@ -235,6 +235,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(0),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG2",
@@ -249,6 +250,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(1),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG3",
@@ -263,6 +265,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_BUCK4_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(2),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG4",
@@ -277,6 +280,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(3),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG5",
@@ -291,6 +295,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(4),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG6",
@@ -305,6 +310,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(5),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG7",
@@ -319,6 +325,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(6),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG8",
@@ -333,6 +340,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(7),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "SWITCH_REG1",
index e2cffe0..fb991ec 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
index 92f6af6..73354ee 100644 (file)
@@ -951,6 +951,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
        void *bufs_va;
        int err = 0, i;
        size_t total_buf_space;
+       bool notify;
 
        vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
        if (!vrp)
@@ -1030,8 +1031,22 @@ static int rpmsg_probe(struct virtio_device *vdev)
                }
        }
 
+       /*
+        * Prepare to kick but don't notify yet - we can't do this before
+        * device is ready.
+        */
+       notify = virtqueue_kick_prepare(vrp->rvq);
+
+       /* From this point on, we can notify and get callbacks. */
+       virtio_device_ready(vdev);
+
        /* tell the remote processor it can start sending messages */
-       virtqueue_kick(vrp->rvq);
+       /*
+        * this might be concurrent with callbacks, but we are only
+        * doing notify, not a full kick here, so that's ok.
+        */
+       if (notify)
+               virtqueue_notify(vrp->rvq);
 
        dev_info(&vdev->dev, "rpmsg host is online\n");
 
index 70a5d94..b283a1a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/suspend.h>
 #include <linux/uaccess.h>
 
 #include "rtc-at91rm9200.h"
@@ -54,6 +55,10 @@ static void __iomem *at91_rtc_regs;
 static int irq;
 static DEFINE_SPINLOCK(at91_rtc_lock);
 static u32 at91_rtc_shadow_imr;
+static bool suspended;
+static DEFINE_SPINLOCK(suspended_lock);
+static unsigned long cached_events;
+static u32 at91_rtc_imr;
 
 static void at91_rtc_write_ier(u32 mask)
 {
@@ -290,7 +295,9 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
        struct rtc_device *rtc = platform_get_drvdata(pdev);
        unsigned int rtsr;
        unsigned long events = 0;
+       int ret = IRQ_NONE;
 
+       spin_lock(&suspended_lock);
        rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr();
        if (rtsr) {             /* this interrupt is shared!  Is it ours? */
                if (rtsr & AT91_RTC_ALARM)
@@ -304,14 +311,22 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
 
                at91_rtc_write(AT91_RTC_SCCR, rtsr);    /* clear status reg */
 
-               rtc_update_irq(rtc, 1, events);
+               if (!suspended) {
+                       rtc_update_irq(rtc, 1, events);
 
-               dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__,
-                       events >> 8, events & 0x000000FF);
+                       dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n",
+                               __func__, events >> 8, events & 0x000000FF);
+               } else {
+                       cached_events |= events;
+                       at91_rtc_write_idr(at91_rtc_imr);
+                       pm_system_wakeup();
+               }
 
-               return IRQ_HANDLED;
+               ret = IRQ_HANDLED;
        }
-       return IRQ_NONE;                /* not handled */
+       spin_unlock(&suspended_lock);
+
+       return ret;
 }
 
 static const struct at91_rtc_config at91rm9200_config = {
@@ -401,8 +416,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                                        AT91_RTC_CALEV);
 
        ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt,
-                               IRQF_SHARED,
-                               "at91_rtc", pdev);
+                              IRQF_SHARED | IRQF_COND_SUSPEND,
+                              "at91_rtc", pdev);
        if (ret) {
                dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
                return ret;
@@ -454,8 +469,6 @@ static void at91_rtc_shutdown(struct platform_device *pdev)
 
 /* AT91RM9200 RTC Power management control */
 
-static u32 at91_rtc_imr;
-
 static int at91_rtc_suspend(struct device *dev)
 {
        /* this IRQ is shared with DBGU and other hardware which isn't
@@ -464,21 +477,42 @@ static int at91_rtc_suspend(struct device *dev)
        at91_rtc_imr = at91_rtc_read_imr()
                        & (AT91_RTC_ALARM|AT91_RTC_SECEV);
        if (at91_rtc_imr) {
-               if (device_may_wakeup(dev))
+               if (device_may_wakeup(dev)) {
+                       unsigned long flags;
+
                        enable_irq_wake(irq);
-               else
+
+                       spin_lock_irqsave(&suspended_lock, flags);
+                       suspended = true;
+                       spin_unlock_irqrestore(&suspended_lock, flags);
+               } else {
                        at91_rtc_write_idr(at91_rtc_imr);
+               }
        }
        return 0;
 }
 
 static int at91_rtc_resume(struct device *dev)
 {
+       struct rtc_device *rtc = dev_get_drvdata(dev);
+
        if (at91_rtc_imr) {
-               if (device_may_wakeup(dev))
+               if (device_may_wakeup(dev)) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&suspended_lock, flags);
+
+                       if (cached_events) {
+                               rtc_update_irq(rtc, 1, cached_events);
+                               cached_events = 0;
+                       }
+
+                       suspended = false;
+                       spin_unlock_irqrestore(&suspended_lock, flags);
+
                        disable_irq_wake(irq);
-               else
-                       at91_rtc_write_ier(at91_rtc_imr);
+               }
+               at91_rtc_write_ier(at91_rtc_imr);
        }
        return 0;
 }
index 2183fd2..5ccaee3 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/suspend.h>
 #include <linux/clk.h>
 
 /*
@@ -77,6 +78,9 @@ struct sam9_rtc {
        unsigned int            gpbr_offset;
        int                     irq;
        struct clk              *sclk;
+       bool                    suspended;
+       unsigned long           events;
+       spinlock_t              lock;
 };
 
 #define rtt_readl(rtc, field) \
@@ -271,14 +275,9 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
        return 0;
 }
 
-/*
- * IRQ handler for the RTC
- */
-static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+static irqreturn_t at91_rtc_cache_events(struct sam9_rtc *rtc)
 {
-       struct sam9_rtc *rtc = _rtc;
        u32 sr, mr;
-       unsigned long events = 0;
 
        /* Shared interrupt may be for another device.  Note: reading
         * SR clears it, so we must only read it in this irq handler!
@@ -290,18 +289,54 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
 
        /* alarm status */
        if (sr & AT91_RTT_ALMS)
-               events |= (RTC_AF | RTC_IRQF);
+               rtc->events |= (RTC_AF | RTC_IRQF);
 
        /* timer update/increment */
        if (sr & AT91_RTT_RTTINC)
-               events |= (RTC_UF | RTC_IRQF);
+               rtc->events |= (RTC_UF | RTC_IRQF);
+
+       return IRQ_HANDLED;
+}
+
+static void at91_rtc_flush_events(struct sam9_rtc *rtc)
+{
+       if (!rtc->events)
+               return;
 
-       rtc_update_irq(rtc->rtcdev, 1, events);
+       rtc_update_irq(rtc->rtcdev, 1, rtc->events);
+       rtc->events = 0;
 
        pr_debug("%s: num=%ld, events=0x%02lx\n", __func__,
-               events >> 8, events & 0x000000FF);
+               rtc->events >> 8, rtc->events & 0x000000FF);
+}
 
-       return IRQ_HANDLED;
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+{
+       struct sam9_rtc *rtc = _rtc;
+       int ret;
+
+       spin_lock(&rtc->lock);
+
+       ret = at91_rtc_cache_events(rtc);
+
+       /* We're called in suspended state */
+       if (rtc->suspended) {
+               /* Mask irqs coming from this peripheral */
+               rtt_writel(rtc, MR,
+                          rtt_readl(rtc, MR) &
+                          ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+               /* Trigger a system wakeup */
+               pm_system_wakeup();
+       } else {
+               at91_rtc_flush_events(rtc);
+       }
+
+       spin_unlock(&rtc->lock);
+
+       return ret;
 }
 
 static const struct rtc_class_ops at91_rtc_ops = {
@@ -421,7 +456,8 @@ static int at91_rtc_probe(struct platform_device *pdev)
 
        /* register irq handler after we know what name we'll use */
        ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
-                               IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc);
+                              IRQF_SHARED | IRQF_COND_SUSPEND,
+                              dev_name(&rtc->rtcdev->dev), rtc);
        if (ret) {
                dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq);
                return ret;
@@ -482,7 +518,12 @@ static int at91_rtc_suspend(struct device *dev)
        rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
        if (rtc->imr) {
                if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) {
+                       unsigned long flags;
+
                        enable_irq_wake(rtc->irq);
+                       spin_lock_irqsave(&rtc->lock, flags);
+                       rtc->suspended = true;
+                       spin_unlock_irqrestore(&rtc->lock, flags);
                        /* don't let RTTINC cause wakeups */
                        if (mr & AT91_RTT_RTTINCIEN)
                                rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
@@ -499,10 +540,18 @@ static int at91_rtc_resume(struct device *dev)
        u32             mr;
 
        if (rtc->imr) {
+               unsigned long flags;
+
                if (device_may_wakeup(dev))
                        disable_irq_wake(rtc->irq);
                mr = rtt_readl(rtc, MR);
                rtt_writel(rtc, MR, mr | rtc->imr);
+
+               spin_lock_irqsave(&rtc->lock, flags);
+               rtc->suspended = false;
+               at91_rtc_cache_events(rtc);
+               at91_rtc_flush_events(rtc);
+               spin_unlock_irqrestore(&rtc->lock, flags);
        }
 
        return 0;
index 8c3bfcb..803869c 100644 (file)
@@ -399,21 +399,21 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
         * of this RTC chip.  We check for it anyways in case support is
         * added in the future.
         */
-       if (unlikely((seconds >= 0xc0) && (seconds <= 0xff)))
+       if (unlikely(seconds >= 0xc0))
                alrm->time.tm_sec = -1;
        else
                alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds,
                                                       RTC_SECS_BCD_MASK,
                                                       RTC_SECS_BIN_MASK);
 
-       if (unlikely((minutes >= 0xc0) && (minutes <= 0xff)))
+       if (unlikely(minutes >= 0xc0))
                alrm->time.tm_min = -1;
        else
                alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes,
                                                       RTC_MINS_BCD_MASK,
                                                       RTC_MINS_BIN_MASK);
 
-       if (unlikely((hours >= 0xc0) && (hours <= 0xff)))
+       if (unlikely(hours >= 0xc0))
                alrm->time.tm_hour = -1;
        else
                alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours,
@@ -472,13 +472,13 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
         * field, and we only support four fields.  We put the support
         * here anyways for the future.
         */
-       if (unlikely((seconds >= 0xc0) && (seconds <= 0xff)))
+       if (unlikely(seconds >= 0xc0))
                seconds = 0xff;
 
-       if (unlikely((minutes >= 0xc0) && (minutes <= 0xff)))
+       if (unlikely(minutes >= 0xc0))
                minutes = 0xff;
 
-       if (unlikely((hours >= 0xc0) && (hours <= 0xff)))
+       if (unlikely(hours >= 0xc0))
                hours = 0xff;
 
        alrm->time.tm_mon       = -1;
@@ -528,7 +528,6 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 /* ----------------------------------------------------------------------- */
 /* /dev/rtcX Interface functions */
 
-#ifdef CONFIG_RTC_INTF_DEV
 /**
  * ds1685_rtc_alarm_irq_enable - replaces ioctl() RTC_AIE on/off.
  * @dev: pointer to device structure.
@@ -557,7 +556,6 @@ ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 
        return 0;
 }
-#endif
 /* ----------------------------------------------------------------------- */
 
 
@@ -1612,7 +1610,7 @@ ds1685_rtc_sysfs_time_regs_show(struct device *dev,
                ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
 
        /* Make sure we actually matched something. */
-       if (!bcd_reg_info && !bin_reg_info)
+       if (!bcd_reg_info || !bin_reg_info)
                return -EINVAL;
 
        /* bcd_reg_info->reg == bin_reg_info->reg. */
@@ -1650,7 +1648,7 @@ ds1685_rtc_sysfs_time_regs_store(struct device *dev,
                return -EINVAL;
 
        /* Make sure we actually matched something. */
-       if (!bcd_reg_info && !bin_reg_info)
+       if (!bcd_reg_info || !bin_reg_info)
                return -EINVAL;
 
        /* Check for a valid range. */
index e2436d1..3a6fd3a 100644 (file)
@@ -413,8 +413,8 @@ static void rtc_mrst_do_remove(struct device *dev)
        mrst->dev = NULL;
 }
 
-#ifdef CONFIG_PM
-static int mrst_suspend(struct device *dev, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int mrst_suspend(struct device *dev)
 {
        struct mrst_rtc *mrst = dev_get_drvdata(dev);
        unsigned char   tmp;
@@ -453,7 +453,7 @@ static int mrst_suspend(struct device *dev, pm_message_t mesg)
  */
 static inline int mrst_poweroff(struct device *dev)
 {
-       return mrst_suspend(dev, PMSG_HIBERNATE);
+       return mrst_suspend(dev);
 }
 
 static int mrst_resume(struct device *dev)
@@ -490,9 +490,11 @@ static int mrst_resume(struct device *dev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(mrst_pm_ops, mrst_suspend, mrst_resume);
+#define MRST_PM_OPS (&mrst_pm_ops)
+
 #else
-#define        mrst_suspend    NULL
-#define        mrst_resume     NULL
+#define MRST_PM_OPS NULL
 
 static inline int mrst_poweroff(struct device *dev)
 {
@@ -529,9 +531,8 @@ static struct platform_driver vrtc_mrst_platform_driver = {
        .remove         = vrtc_mrst_platform_remove,
        .shutdown       = vrtc_mrst_platform_shutdown,
        .driver = {
-               .name           = (char *) driver_name,
-               .suspend        = mrst_suspend,
-               .resume         = mrst_resume,
+               .name   = driver_name,
+               .pm     = MRST_PM_OPS,
        }
 };
 
index 4241eea..f4cf685 100644 (file)
@@ -849,6 +849,7 @@ static struct s3c_rtc_data const s3c2443_rtc_data = {
 
 static struct s3c_rtc_data const s3c6410_rtc_data = {
        .max_user_freq          = 32768,
+       .needs_src_clk          = true,
        .irq_handler            = s3c6410_rtc_irq,
        .set_freq               = s3c6410_rtc_setfreq,
        .enable_tick            = s3c6410_rtc_enable_tick,
index 96128cb..da21281 100644 (file)
@@ -547,7 +547,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
         * parse input
         */
        num_of_segments = 0;
-       for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
+       for (i = 0; (i < count && (buf[i] != '\0') && (buf[i] != '\n')); i++) {
                for (j = i; (buf[j] != ':') &&
                        (buf[j] != '\0') &&
                        (buf[j] != '\n') &&
index 09db452..7497ddd 100644 (file)
@@ -92,7 +92,7 @@ bool scm_reserve_cluster(struct scm_request *scmrq)
                        add = 0;
                        continue;
                }
-               for (pos = 0; pos <= iter->aob->request.msb_count; pos++) {
+               for (pos = 0; pos < iter->aob->request.msb_count; pos++) {
                        if (clusters_intersect(req, iter->request[pos]) &&
                            (rq_data_dir(req) == WRITE ||
                             rq_data_dir(iter->request[pos]) == WRITE)) {
index 9219953..d9afc51 100644 (file)
@@ -6815,7 +6815,8 @@ static struct ata_port_operations ipr_sata_ops = {
 };
 
 static struct ata_port_info sata_port_info = {
-       .flags          = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
+       .flags          = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
+                         ATA_FLAG_SAS_HOST,
        .pio_mask       = ATA_PIO4_ONLY,
        .mwdma_mask     = ATA_MWDMA2,
        .udma_mask      = ATA_UDMA6,
index 932d9cc..9c706d8 100644 (file)
@@ -547,7 +547,8 @@ static struct ata_port_operations sas_sata_ops = {
 };
 
 static struct ata_port_info sata_port_info = {
-       .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ,
+       .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ |
+                ATA_FLAG_SAS_HOST,
        .pio_mask = ATA_PIO4,
        .mwdma_mask = ATA_MWDMA2,
        .udma_mask = ATA_UDMA6,
index 62b58d3..60de662 100644 (file)
@@ -500,6 +500,7 @@ static void sas_revalidate_domain(struct work_struct *work)
        struct sas_discovery_event *ev = to_sas_discovery_event(work);
        struct asd_sas_port *port = ev->port;
        struct sas_ha_struct *ha = port->ha;
+       struct domain_device *ddev = port->port_dev;
 
        /* prevent revalidation from finding sata links in recovery */
        mutex_lock(&ha->disco_mutex);
@@ -514,8 +515,9 @@ static void sas_revalidate_domain(struct work_struct *work)
        SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
                    task_pid_nr(current));
 
-       if (port->port_dev)
-               res = sas_ex_revalidate_domain(port->port_dev);
+       if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
+                    ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE))
+               res = sas_ex_revalidate_domain(ddev);
 
        SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
                    port->id, task_pid_nr(current), res);
index 99f43b7..ab4879e 100644 (file)
@@ -1596,7 +1596,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        /*
         * Finally register the new FC Nexus with TCM
         */
-       __transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
+       transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
 
        return 0;
 }
index f3ee439..cd4c293 100644 (file)
@@ -81,7 +81,9 @@ static int __init sh_pm_runtime_init(void)
                if (!of_machine_is_compatible("renesas,emev2") &&
                    !of_machine_is_compatible("renesas,r7s72100") &&
                    !of_machine_is_compatible("renesas,r8a73a4") &&
+#ifndef CONFIG_PM_GENERIC_DOMAINS_OF
                    !of_machine_is_compatible("renesas,r8a7740") &&
+#endif
                    !of_machine_is_compatible("renesas,r8a7778") &&
                    !of_machine_is_compatible("renesas,r8a7779") &&
                    !of_machine_is_compatible("renesas,r8a7790") &&
index 9af7841..06de340 100644 (file)
@@ -764,17 +764,17 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
                        (unsigned long long)xfer->rx_dma);
        }
 
-       /* REVISIT: We're waiting for ENDRX before we start the next
+       /* REVISIT: We're waiting for RXBUFF before we start the next
         * transfer because we need to handle some difficult timing
-        * issues otherwise. If we wait for ENDTX in one transfer and
-        * then starts waiting for ENDRX in the next, it's difficult
-        * to tell the difference between the ENDRX interrupt we're
-        * actually waiting for and the ENDRX interrupt of the
+        * issues otherwise. If we wait for TXBUFE in one transfer and
+        * then starts waiting for RXBUFF in the next, it's difficult
+        * to tell the difference between the RXBUFF interrupt we're
+        * actually waiting for and the RXBUFF interrupt of the
         * previous transfer.
         *
         * It should be doable, though. Just not now...
         */
-       spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
+       spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES));
        spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
 }
 
index a0197fd..4f8c798 100644 (file)
@@ -108,7 +108,8 @@ static void dw_spi_dma_tx_done(void *arg)
 {
        struct dw_spi *dws = arg;
 
-       if (test_and_clear_bit(TX_BUSY, &dws->dma_chan_busy) & BIT(RX_BUSY))
+       clear_bit(TX_BUSY, &dws->dma_chan_busy);
+       if (test_bit(RX_BUSY, &dws->dma_chan_busy))
                return;
        dw_spi_xfer_done(dws);
 }
@@ -139,6 +140,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws)
                                1,
                                DMA_MEM_TO_DEV,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!txdesc)
+               return NULL;
+
        txdesc->callback = dw_spi_dma_tx_done;
        txdesc->callback_param = dws;
 
@@ -153,7 +157,8 @@ static void dw_spi_dma_rx_done(void *arg)
 {
        struct dw_spi *dws = arg;
 
-       if (test_and_clear_bit(RX_BUSY, &dws->dma_chan_busy) & BIT(TX_BUSY))
+       clear_bit(RX_BUSY, &dws->dma_chan_busy);
+       if (test_bit(TX_BUSY, &dws->dma_chan_busy))
                return;
        dw_spi_xfer_done(dws);
 }
@@ -184,6 +189,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
                                1,
                                DMA_DEV_TO_MEM,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!rxdesc)
+               return NULL;
+
        rxdesc->callback = dw_spi_dma_rx_done;
        rxdesc->callback_param = dws;
 
index 5ba3310..6d331e0 100644 (file)
@@ -36,13 +36,13 @@ struct spi_pci_desc {
 
 static struct spi_pci_desc spi_pci_mid_desc_1 = {
        .setup = dw_spi_mid_init,
-       .num_cs = 32,
+       .num_cs = 5,
        .bus_num = 0,
 };
 
 static struct spi_pci_desc spi_pci_mid_desc_2 = {
        .setup = dw_spi_mid_init,
-       .num_cs = 4,
+       .num_cs = 2,
        .bus_num = 1,
 };
 
index 5a97a62..4847afb 100644 (file)
@@ -621,14 +621,14 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
        if (!dws->fifo_len) {
                u32 fifo;
 
-               for (fifo = 2; fifo <= 256; fifo++) {
+               for (fifo = 1; fifo < 256; fifo++) {
                        dw_writew(dws, DW_SPI_TXFLTR, fifo);
                        if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
                                break;
                }
                dw_writew(dws, DW_SPI_TXFLTR, 0);
 
-               dws->fifo_len = (fifo == 2) ? 0 : fifo - 1;
+               dws->fifo_len = (fifo == 1) ? 0 : fifo;
                dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
        }
 }
index c01567d..e649bc7 100644 (file)
@@ -459,6 +459,13 @@ static int img_spfi_transfer_one(struct spi_master *master,
        unsigned long flags;
        int ret;
 
+       if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
+               dev_err(spfi->dev,
+                       "Transfer length (%d) is greater than the max supported (%d)",
+                       xfer->len, SPFI_TRANSACTION_TSIZE_MASK);
+               return -EINVAL;
+       }
+
        /*
         * Stop all DMA and reset the controller if the previous transaction
         * timed-out and never completed it's DMA.
index 89ca162..ee513a8 100644 (file)
@@ -534,12 +534,12 @@ static void giveback(struct pl022 *pl022)
        pl022->cur_msg = NULL;
        pl022->cur_transfer = NULL;
        pl022->cur_chip = NULL;
-       spi_finalize_current_message(pl022->master);
 
        /* disable the SPI/SSP operation */
        writew((readw(SSP_CR1(pl022->virtbase)) &
                (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
 
+       spi_finalize_current_message(pl022->master);
 }
 
 /**
index ff9cdbd..2b2c359 100644 (file)
@@ -498,7 +498,7 @@ static int spi_qup_probe(struct platform_device *pdev)
        struct resource *res;
        struct device *dev;
        void __iomem *base;
-       u32 max_freq, iomode;
+       u32 max_freq, iomode, num_cs;
        int ret, irq, size;
 
        dev = &pdev->dev;
@@ -550,10 +550,11 @@ static int spi_qup_probe(struct platform_device *pdev)
        }
 
        /* use num-cs unless not present or out of range */
-       if (of_property_read_u16(dev->of_node, "num-cs",
-                       &master->num_chipselect) ||
-                       (master->num_chipselect > SPI_NUM_CHIPSELECTS))
+       if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) ||
+           num_cs > SPI_NUM_CHIPSELECTS)
                master->num_chipselect = SPI_NUM_CHIPSELECTS;
+       else
+               master->num_chipselect = num_cs;
 
        master->bus_num = pdev->id;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
index 884a716..5c06168 100644 (file)
@@ -101,6 +101,7 @@ struct ti_qspi {
 #define QSPI_FLEN(n)                   ((n - 1) << 0)
 
 /* STATUS REGISTER */
+#define BUSY                           0x01
 #define WC                             0x02
 
 /* INTERRUPT REGISTER */
@@ -199,6 +200,21 @@ static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
        ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
 }
 
+static inline u32 qspi_is_busy(struct ti_qspi *qspi)
+{
+       u32 stat;
+       unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
+
+       stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
+       while ((stat & BUSY) && time_after(timeout, jiffies)) {
+               cpu_relax();
+               stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
+       }
+
+       WARN(stat & BUSY, "qspi busy\n");
+       return stat & BUSY;
+}
+
 static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
 {
        int wlen, count;
@@ -211,6 +227,9 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
        wlen = t->bits_per_word >> 3;   /* in bytes */
 
        while (count) {
+               if (qspi_is_busy(qspi))
+                       return -EBUSY;
+
                switch (wlen) {
                case 1:
                        dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
@@ -266,6 +285,9 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
 
        while (count) {
                dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
+               if (qspi_is_busy(qspi))
+                       return -EBUSY;
+
                ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
                if (!wait_for_completion_timeout(&qspi->transfer_complete,
                                                 QSPI_COMPLETION_TIMEOUT)) {
index c64a3e5..57a1950 100644 (file)
@@ -1105,13 +1105,14 @@ void spi_finalize_current_message(struct spi_master *master)
                                "failed to unprepare message: %d\n", ret);
                }
        }
+
+       trace_spi_message_done(mesg);
+
        master->cur_msg_prepared = false;
 
        mesg->state = NULL;
        if (mesg->complete)
                mesg->complete(mesg->context);
-
-       trace_spi_message_done(mesg);
 }
 EXPORT_SYMBOL_GPL(spi_finalize_current_message);
 
index 9800c01..3f72451 100644 (file)
@@ -426,7 +426,6 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
                                unsigned int *data)
 {
        struct pci1710_private *devpriv = dev->private;
-       unsigned int chan = CR_CHAN(insn->chanspec);
        int ret = 0;
        int i;
 
@@ -447,7 +446,7 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
                if (ret)
                        break;
 
-               ret = pci171x_ai_read_sample(dev, s, chan, &val);
+               ret = pci171x_ai_read_sample(dev, s, 0, &val);
                if (ret)
                        break;
 
index dbdea71..e856f01 100644 (file)
@@ -91,9 +91,10 @@ unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
                        stalled++;
                        if (stalled > 10)
                                break;
+               } else {
+                       residue = new_residue;
+                       stalled = 0;
                }
-               residue = new_residue;
-               stalled = 0;
        }
        return residue;
 }
index e371183..a090668 100644 (file)
@@ -103,11 +103,6 @@ enum vmk80xx_model {
        VMK8061_MODEL
 };
 
-struct firmware_version {
-       unsigned char ic3_vers[32];     /* USB-Controller */
-       unsigned char ic6_vers[32];     /* CPU */
-};
-
 static const struct comedi_lrange vmk8061_range = {
        2, {
                UNI_RANGE(5),
@@ -156,68 +151,12 @@ static const struct vmk80xx_board vmk80xx_boardinfo[] = {
 struct vmk80xx_private {
        struct usb_endpoint_descriptor *ep_rx;
        struct usb_endpoint_descriptor *ep_tx;
-       struct firmware_version fw;
        struct semaphore limit_sem;
        unsigned char *usb_rx_buf;
        unsigned char *usb_tx_buf;
        enum vmk80xx_model model;
 };
 
-static int vmk80xx_check_data_link(struct comedi_device *dev)
-{
-       struct vmk80xx_private *devpriv = dev->private;
-       struct usb_device *usb = comedi_to_usb_dev(dev);
-       unsigned int tx_pipe;
-       unsigned int rx_pipe;
-       unsigned char tx[1];
-       unsigned char rx[2];
-
-       tx_pipe = usb_sndbulkpipe(usb, 0x01);
-       rx_pipe = usb_rcvbulkpipe(usb, 0x81);
-
-       tx[0] = VMK8061_CMD_RD_PWR_STAT;
-
-       /*
-        * Check that IC6 (PIC16F871) is powered and
-        * running and the data link between IC3 and
-        * IC6 is working properly
-        */
-       usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
-       usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10);
-
-       return (int)rx[1];
-}
-
-static void vmk80xx_read_eeprom(struct comedi_device *dev, int flag)
-{
-       struct vmk80xx_private *devpriv = dev->private;
-       struct usb_device *usb = comedi_to_usb_dev(dev);
-       unsigned int tx_pipe;
-       unsigned int rx_pipe;
-       unsigned char tx[1];
-       unsigned char rx[64];
-       int cnt;
-
-       tx_pipe = usb_sndbulkpipe(usb, 0x01);
-       rx_pipe = usb_rcvbulkpipe(usb, 0x81);
-
-       tx[0] = VMK8061_CMD_RD_VERSION;
-
-       /*
-        * Read the firmware version info of IC3 and
-        * IC6 from the internal EEPROM of the IC
-        */
-       usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
-       usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10);
-
-       rx[cnt] = '\0';
-
-       if (flag & IC3_VERSION)
-               strncpy(devpriv->fw.ic3_vers, rx + 1, 24);
-       else                    /* IC6_VERSION */
-               strncpy(devpriv->fw.ic6_vers, rx + 25, 24);
-}
-
 static void vmk80xx_do_bulk_msg(struct comedi_device *dev)
 {
        struct vmk80xx_private *devpriv = dev->private;
@@ -878,16 +817,6 @@ static int vmk80xx_auto_attach(struct comedi_device *dev,
 
        usb_set_intfdata(intf, devpriv);
 
-       if (devpriv->model == VMK8061_MODEL) {
-               vmk80xx_read_eeprom(dev, IC3_VERSION);
-               dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
-
-               if (vmk80xx_check_data_link(dev)) {
-                       vmk80xx_read_eeprom(dev, IC6_VERSION);
-                       dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
-               }
-       }
-
        if (devpriv->model == VMK8055_MODEL)
                vmk80xx_reset_device(dev);
 
index 2418302..6d5b38d 100644 (file)
@@ -38,6 +38,7 @@ config IIO_SIMPLE_DUMMY_EVENTS
 config IIO_SIMPLE_DUMMY_BUFFER
        bool "Buffered capture support"
        select IIO_BUFFER
+       select IIO_TRIGGER
        select IIO_KFIFO_BUF
        help
          Add buffered data capture to the simple dummy driver.
index d9d6fad..8161743 100644 (file)
@@ -214,11 +214,17 @@ struct mxs_lradc {
        unsigned long           is_divided;
 
        /*
-        * Touchscreen LRADC channels receives a private slot in the CTRL4
-        * register, the slot #7. Therefore only 7 slots instead of 8 in the
-        * CTRL4 register can be mapped to LRADC channels when using the
-        * touchscreen.
-        *
+        * When the touchscreen is enabled, we give it two private virtual
+        * channels: #6 and #7. This means that only 6 virtual channels (instead
+        * of 8) will be available for buffered capture.
+        */
+#define TOUCHSCREEN_VCHANNEL1          7
+#define TOUCHSCREEN_VCHANNEL2          6
+#define BUFFER_VCHANS_LIMITED          0x3f
+#define BUFFER_VCHANS_ALL              0xff
+       u8                      buffer_vchans;
+
+       /*
         * Furthermore, certain LRADC channels are shared between touchscreen
         * and/or touch-buttons and generic LRADC block. Therefore when using
         * either of these, these channels are not available for the regular
@@ -342,6 +348,9 @@ struct mxs_lradc {
 #define        LRADC_CTRL4                             0x140
 #define        LRADC_CTRL4_LRADCSELECT_MASK(n)         (0xf << ((n) * 4))
 #define        LRADC_CTRL4_LRADCSELECT_OFFSET(n)       ((n) * 4)
+#define        LRADC_CTRL4_LRADCSELECT(n, x) \
+                               (((x) << LRADC_CTRL4_LRADCSELECT_OFFSET(n)) & \
+                               LRADC_CTRL4_LRADCSELECT_MASK(n))
 
 #define LRADC_RESOLUTION                       12
 #define LRADC_SINGLE_SAMPLE_MASK               ((1 << LRADC_RESOLUTION) - 1)
@@ -416,6 +425,14 @@ static bool mxs_lradc_check_touch_event(struct mxs_lradc *lradc)
                                        LRADC_STATUS_TOUCH_DETECT_RAW);
 }
 
+static void mxs_lradc_map_channel(struct mxs_lradc *lradc, unsigned vch,
+                                 unsigned ch)
+{
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(vch),
+                               LRADC_CTRL4);
+       mxs_lradc_reg_set(lradc, LRADC_CTRL4_LRADCSELECT(vch, ch), LRADC_CTRL4);
+}
+
 static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
 {
        /*
@@ -450,12 +467,8 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
                LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
                        LRADC_DELAY(3));
 
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
-                       LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
-                       LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch), LRADC_CTRL1);
 
-       /* wake us again, when the complete conversion is done */
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch), LRADC_CTRL1);
        /*
         * after changing the touchscreen plates setting
         * the signals need some initial time to settle. Start the
@@ -509,12 +522,8 @@ static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1,
                LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
                                        LRADC_DELAY(3));
 
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
-                       LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
-                       LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch2), LRADC_CTRL1);
 
-       /* wake us again, when the conversions are done */
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch2), LRADC_CTRL1);
        /*
         * after changing the touchscreen plates setting
         * the signals need some initial time to settle. Start the
@@ -580,36 +589,6 @@ static unsigned mxs_lradc_read_ts_pressure(struct mxs_lradc *lradc,
 #define TS_CH_XM 4
 #define TS_CH_YM 5
 
-static int mxs_lradc_read_ts_channel(struct mxs_lradc *lradc)
-{
-       u32 reg;
-       int val;
-
-       reg = readl(lradc->base + LRADC_CTRL1);
-
-       /* only channels 3 to 5 are of interest here */
-       if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YP)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YP) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_YP), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_YP);
-       } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_XM)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_XM) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_XM), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_XM);
-       } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YM)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YM) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_YM), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_YM);
-       } else {
-               return -EIO;
-       }
-
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
-
-       return val;
-}
-
 /*
  * YP(open)--+-------------+
  *           |             |--+
@@ -653,7 +632,8 @@ static void mxs_lradc_prepare_x_pos(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_X;
-       mxs_lradc_setup_ts_channel(lradc, TS_CH_YP);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YP);
+       mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
 }
 
 /*
@@ -674,7 +654,8 @@ static void mxs_lradc_prepare_y_pos(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_Y;
-       mxs_lradc_setup_ts_channel(lradc, TS_CH_XM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_XM);
+       mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
 }
 
 /*
@@ -695,7 +676,10 @@ static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_PRESSURE;
-       mxs_lradc_setup_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL2, TS_CH_XP);
+       mxs_lradc_setup_ts_pressure(lradc, TOUCHSCREEN_VCHANNEL2,
+                                               TOUCHSCREEN_VCHANNEL1);
 }
 
 static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
@@ -708,6 +692,19 @@ static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
 }
 
+static void mxs_lradc_start_touch_event(struct mxs_lradc *lradc)
+{
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+                               LRADC_CTRL1);
+       mxs_lradc_reg_set(lradc,
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
+       /*
+        * start with the Y-pos, because it uses nearly the same plate
+        * settings like the touch detection
+        */
+       mxs_lradc_prepare_y_pos(lradc);
+}
+
 static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc)
 {
        input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos);
@@ -725,10 +722,12 @@ static void mxs_lradc_complete_touch_event(struct mxs_lradc *lradc)
         * start a dummy conversion to burn time to settle the signals
         * note: we are not interested in the conversion's value
         */
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(5));
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(5), LRADC_CTRL1);
-       mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << 5) |
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(TOUCHSCREEN_VCHANNEL1));
+       mxs_lradc_reg_clear(lradc,
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
+       mxs_lradc_reg_wrt(lradc,
+               LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
                LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */
                        LRADC_DELAY(2));
 }
@@ -760,59 +759,45 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid)
 
        /* if it is released, wait for the next touch via IRQ */
        lradc->cur_plate = LRADC_TOUCH;
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1);
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ |
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
        mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
 }
 
 /* touchscreen's state machine */
 static void mxs_lradc_handle_touch(struct mxs_lradc *lradc)
 {
-       int val;
-
        switch (lradc->cur_plate) {
        case LRADC_TOUCH:
-               /*
-                * start with the Y-pos, because it uses nearly the same plate
-                * settings like the touch detection
-                */
-               if (mxs_lradc_check_touch_event(lradc)) {
-                       mxs_lradc_reg_clear(lradc,
-                                       LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
-                                       LRADC_CTRL1);
-                       mxs_lradc_prepare_y_pos(lradc);
-               }
+               if (mxs_lradc_check_touch_event(lradc))
+                       mxs_lradc_start_touch_event(lradc);
                mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ,
                                        LRADC_CTRL1);
                return;
 
        case LRADC_SAMPLE_Y:
-               val = mxs_lradc_read_ts_channel(lradc);
-               if (val < 0) {
-                       mxs_lradc_enable_touch_detection(lradc); /* re-start */
-                       return;
-               }
-               lradc->ts_y_pos = val;
+               lradc->ts_y_pos = mxs_lradc_read_raw_channel(lradc,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_prepare_x_pos(lradc);
                return;
 
        case LRADC_SAMPLE_X:
-               val = mxs_lradc_read_ts_channel(lradc);
-               if (val < 0) {
-                       mxs_lradc_enable_touch_detection(lradc); /* re-start */
-                       return;
-               }
-               lradc->ts_x_pos = val;
+               lradc->ts_x_pos = mxs_lradc_read_raw_channel(lradc,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_prepare_pressure(lradc);
                return;
 
        case LRADC_SAMPLE_PRESSURE:
-               lradc->ts_pressure =
-                       mxs_lradc_read_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
+               lradc->ts_pressure = mxs_lradc_read_ts_pressure(lradc,
+                                                       TOUCHSCREEN_VCHANNEL2,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_complete_touch_event(lradc);
                return;
 
        case LRADC_SAMPLE_VALID:
-               val = mxs_lradc_read_ts_channel(lradc); /* ignore the value */
                mxs_lradc_finish_touch_event(lradc, 1);
                break;
        }
@@ -844,9 +829,9 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val)
         * used if doing raw sampling.
         */
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
+               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0),
                        LRADC_CTRL1);
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+       mxs_lradc_reg_clear(lradc, 0x1, LRADC_CTRL0);
 
        /* Enable / disable the divider per requirement */
        if (test_bit(chan, &lradc->is_divided))
@@ -1090,9 +1075,8 @@ static void mxs_lradc_disable_ts(struct mxs_lradc *lradc)
 {
        /* stop all interrupts from firing */
        mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
-               LRADC_CTRL1_LRADC_IRQ_EN(2) | LRADC_CTRL1_LRADC_IRQ_EN(3) |
-               LRADC_CTRL1_LRADC_IRQ_EN(4) | LRADC_CTRL1_LRADC_IRQ_EN(5),
-               LRADC_CTRL1);
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
 
        /* Power-down touchscreen touch-detect circuitry. */
        mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
@@ -1158,26 +1142,31 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
        struct iio_dev *iio = data;
        struct mxs_lradc *lradc = iio_priv(iio);
        unsigned long reg = readl(lradc->base + LRADC_CTRL1);
+       uint32_t clr_irq = mxs_lradc_irq_mask(lradc);
        const uint32_t ts_irq_mask =
                LRADC_CTRL1_TOUCH_DETECT_IRQ |
-               LRADC_CTRL1_LRADC_IRQ(2) |
-               LRADC_CTRL1_LRADC_IRQ(3) |
-               LRADC_CTRL1_LRADC_IRQ(4) |
-               LRADC_CTRL1_LRADC_IRQ(5);
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
 
        if (!(reg & mxs_lradc_irq_mask(lradc)))
                return IRQ_NONE;
 
-       if (lradc->use_touchscreen && (reg & ts_irq_mask))
+       if (lradc->use_touchscreen && (reg & ts_irq_mask)) {
                mxs_lradc_handle_touch(lradc);
 
-       if (iio_buffer_enabled(iio))
-               iio_trigger_poll(iio->trig);
-       else if (reg & LRADC_CTRL1_LRADC_IRQ(0))
+               /* Make sure we don't clear the next conversion's interrupt. */
+               clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+                               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));
+       }
+
+       if (iio_buffer_enabled(iio)) {
+               if (reg & lradc->buffer_vchans)
+                       iio_trigger_poll(iio->trig);
+       } else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) {
                complete(&lradc->completion);
+       }
 
-       mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc),
-                       LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1);
 
        return IRQ_HANDLED;
 }
@@ -1289,9 +1278,10 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
        }
 
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
-                                                       LRADC_CTRL1);
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+               mxs_lradc_reg_clear(lradc,
+                       lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+                       LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
 
        for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
                ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
@@ -1324,10 +1314,11 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio)
        mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK |
                                        LRADC_DELAY_KICK, LRADC_DELAY(0));
 
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+       mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
-                                       LRADC_CTRL1);
+               mxs_lradc_reg_clear(lradc,
+                       lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+                       LRADC_CTRL1);
 
        kfree(lradc->buffer);
        mutex_unlock(&lradc->lock);
@@ -1353,7 +1344,7 @@ static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio,
        if (lradc->use_touchbutton)
                rsvd_chans++;
        if (lradc->use_touchscreen)
-               rsvd_chans++;
+               rsvd_chans += 2;
 
        /* Test for attempts to map channels with special mode of operation. */
        if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS))
@@ -1413,6 +1404,13 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
                .channel = 8,
                .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
        },
+       /* Hidden channel to keep indexes */
+       {
+               .type = IIO_TEMP,
+               .indexed = 1,
+               .scan_index = -1,
+               .channel = 9,
+       },
        MXS_ADC_CHAN(10, IIO_VOLTAGE),  /* VDDIO */
        MXS_ADC_CHAN(11, IIO_VOLTAGE),  /* VTH */
        MXS_ADC_CHAN(12, IIO_VOLTAGE),  /* VDDA */
@@ -1583,6 +1581,11 @@ static int mxs_lradc_probe(struct platform_device *pdev)
 
        touch_ret = mxs_lradc_probe_touchscreen(lradc, node);
 
+       if (touch_ret == 0)
+               lradc->buffer_vchans = BUFFER_VCHANS_LIMITED;
+       else
+               lradc->buffer_vchans = BUFFER_VCHANS_ALL;
+
        /* Grab all IRQ sources */
        for (i = 0; i < of_cfg->irq_count; i++) {
                lradc->irq[i] = platform_get_irq(pdev, i);
index fd171d8..90cc18b 100644 (file)
@@ -592,6 +592,7 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
        mutex_init(&data->lock);
 
        indio_dev->dev.parent = dev;
+       indio_dev->name = dev->driver->name;
        indio_dev->info = &hmc5843_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = data->variant->channels;
index 017d2f8..c17893b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -68,7 +69,7 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev,
                break;
        case IIO_ANGL_VEL:
                vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
-               vel = (vel << 4) >> 4;
+               vel = sign_extend32(vel, 11);
                *val = vel;
                break;
        default:
index 4324282..03b2a90 100644 (file)
@@ -330,16 +330,6 @@ static void device_init_registers(struct vnt_private *pDevice)
        /* zonetype initial */
        pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
 
-       /* Get RFType */
-       pDevice->byRFType = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RFTYPE);
-
-       /* force change RevID for VT3253 emu */
-       if ((pDevice->byRFType & RF_EMU) != 0)
-                       pDevice->byRevId = 0x80;
-
-       pDevice->byRFType &= RF_MASK;
-       pr_debug("pDevice->byRFType = %x\n", pDevice->byRFType);
-
        if (!pDevice->bZoneRegExist)
                pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
 
@@ -1187,12 +1177,14 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        PSTxDesc head_td;
-       u32 dma_idx = TYPE_AC0DMA;
+       u32 dma_idx;
        unsigned long flags;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (!ieee80211_is_data(hdr->frame_control))
+       if (ieee80211_is_data(hdr->frame_control))
+               dma_idx = TYPE_AC0DMA;
+       else
                dma_idx = TYPE_TXDMA0;
 
        if (AVAIL_TD(priv, dma_idx) < 1) {
@@ -1206,6 +1198,9 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->pTDInfo->skb = skb;
 
+       if (dma_idx == TYPE_AC0DMA)
+               head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
+
        priv->iTDUsed[dma_idx]++;
 
        /* Take ownership */
@@ -1234,13 +1229,10 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma);
 
-       if (dma_idx == TYPE_AC0DMA) {
-               head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
-
+       if (head_td->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)
                MACvTransmitAC0(priv->PortOffset);
-       } else {
+       else
                MACvTransmit0(priv->PortOffset);
-       }
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1778,6 +1770,12 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
        MACvInitialize(priv->PortOffset);
        MACvReadEtherAddress(priv->PortOffset, priv->abyCurrentNetAddr);
 
+       /* Get RFType */
+       priv->byRFType = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_RFTYPE);
+       priv->byRFType &= RF_MASK;
+
+       dev_dbg(&pcid->dev, "RF Type = %x\n", priv->byRFType);
+
        device_get_options(priv);
        device_set_options(priv);
        /* Mask out the options cannot be set to the chip */
index 941b2ad..7626f63 100644 (file)
@@ -794,6 +794,7 @@ bool RFbSetPower(
                break;
        case RATE_6M:
        case RATE_9M:
+       case RATE_12M:
        case RATE_18M:
                byPwr = priv->abyOFDMPwrTbl[uCH];
                if (priv->byRFType == RF_UW2452)
index c42cde5..c4286cc 100644 (file)
@@ -640,6 +640,7 @@ int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel)
                break;
        case RATE_6M:
        case RATE_9M:
+       case RATE_12M:
        case RATE_18M:
        case RATE_24M:
        case RATE_36M:
index 50bad55..2accb6e 100644 (file)
@@ -4256,11 +4256,17 @@ int iscsit_close_connection(
        pr_debug("Closing iSCSI connection CID %hu on SID:"
                " %u\n", conn->cid, sess->sid);
        /*
-        * Always up conn_logout_comp just in case the RX Thread is sleeping
-        * and the logout response never got sent because the connection
-        * failed.
+        * Always up conn_logout_comp for the traditional TCP case just in case
+        * the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout
+        * response never got sent because the connection failed.
+        *
+        * However for iser-target, isert_wait4logout() is using conn_logout_comp
+        * to signal logout response TX interrupt completion.  Go ahead and skip
+        * this for iser since isert_rx_opcode() does not wait on logout failure,
+        * and to avoid iscsi_conn pointer dereference in iser-target code.
         */
-       complete(&conn->conn_logout_comp);
+       if (conn->conn_transport->transport_type == ISCSI_TCP)
+               complete(&conn->conn_logout_comp);
 
        iscsi_release_thread_set(conn);
 
index 1c197ba..bdd8731 100644 (file)
@@ -22,7 +22,6 @@
 #include <target/target_core_fabric.h>
 
 #include <target/iscsi/iscsi_target_core.h>
-#include <target/iscsi/iscsi_transport.h>
 #include "iscsi_target_seq_pdu_list.h"
 #include "iscsi_target_tq.h"
 #include "iscsi_target_erl0.h"
@@ -940,8 +939,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
 
        if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
                spin_unlock_bh(&conn->state_lock);
-               if (conn->conn_transport->transport_type == ISCSI_TCP)
-                       iscsit_close_connection(conn);
+               iscsit_close_connection(conn);
                return;
        }
 
index 6b3c329..c36bd7c 100644 (file)
@@ -953,11 +953,8 @@ static int tcm_loop_make_nexus(
                transport_free_session(tl_nexus->se_sess);
                goto out;
        }
-       /*
-        * Now, register the SAS I_T Nexus as active with the call to
-        * transport_register_session()
-        */
-       __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
+       /* Now, register the SAS I_T Nexus as active. */
+       transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
                        tl_nexus->se_sess, tl_nexus);
        tl_tpg->tl_nexus = tl_nexus;
        pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated"
index 58f49ff..79b4ec3 100644 (file)
@@ -650,6 +650,18 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
        return aligned_max_sectors;
 }
 
+bool se_dev_check_wce(struct se_device *dev)
+{
+       bool wce = false;
+
+       if (dev->transport->get_write_cache)
+               wce = dev->transport->get_write_cache(dev);
+       else if (dev->dev_attrib.emulate_write_cache > 0)
+               wce = true;
+
+       return wce;
+}
+
 int se_dev_set_max_unmap_lba_count(
        struct se_device *dev,
        u32 max_unmap_lba_count)
@@ -767,6 +779,16 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
                pr_err("Illegal value %d\n", flag);
                return -EINVAL;
        }
+       if (flag &&
+           dev->transport->get_write_cache) {
+               pr_err("emulate_fua_write not supported for this device\n");
+               return -EINVAL;
+       }
+       if (dev->export_count) {
+               pr_err("emulate_fua_write cannot be changed with active"
+                      " exports: %d\n", dev->export_count);
+               return -EINVAL;
+       }
        dev->dev_attrib.emulate_fua_write = flag;
        pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n",
                        dev, dev->dev_attrib.emulate_fua_write);
@@ -801,7 +823,11 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
                pr_err("emulate_write_cache not supported for this device\n");
                return -EINVAL;
        }
-
+       if (dev->export_count) {
+               pr_err("emulate_write_cache cannot be changed with active"
+                      " exports: %d\n", dev->export_count);
+               return -EINVAL;
+       }
        dev->dev_attrib.emulate_write_cache = flag;
        pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
                        dev, dev->dev_attrib.emulate_write_cache);
@@ -1534,8 +1560,6 @@ int target_configure_device(struct se_device *dev)
        ret = dev->transport->configure_device(dev);
        if (ret)
                goto out;
-       dev->dev_flags |= DF_CONFIGURED;
-
        /*
         * XXX: there is not much point to have two different values here..
         */
@@ -1597,6 +1621,8 @@ int target_configure_device(struct se_device *dev)
        list_add_tail(&dev->g_dev_node, &g_device_list);
        mutex_unlock(&g_device_mutex);
 
+       dev->dev_flags |= DF_CONFIGURED;
+
        return 0;
 
 out_free_alua:
index 1045dcd..f6c954c 100644 (file)
@@ -1121,7 +1121,7 @@ static u32 pscsi_get_device_type(struct se_device *dev)
        struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
        struct scsi_device *sd = pdv->pdv_sd;
 
-       return sd->type;
+       return (sd) ? sd->type : TYPE_NO_LUN;
 }
 
 static sector_t pscsi_get_blocks(struct se_device *dev)
index 9a2f9d3..3e72974 100644 (file)
@@ -708,8 +708,7 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
                }
        }
        if (cdb[1] & 0x8) {
-               if (!dev->dev_attrib.emulate_fua_write ||
-                   !dev->dev_attrib.emulate_write_cache) {
+               if (!dev->dev_attrib.emulate_fua_write || !se_dev_check_wce(dev)) {
                        pr_err("Got CDB: 0x%02x with FUA bit set, but device"
                               " does not advertise support for FUA write\n",
                               cdb[0]);
index 460e931..6c8bd6b 100644 (file)
@@ -454,19 +454,6 @@ check_scsi_name:
 }
 EXPORT_SYMBOL(spc_emulate_evpd_83);
 
-static bool
-spc_check_dev_wce(struct se_device *dev)
-{
-       bool wce = false;
-
-       if (dev->transport->get_write_cache)
-               wce = dev->transport->get_write_cache(dev);
-       else if (dev->dev_attrib.emulate_write_cache > 0)
-               wce = true;
-
-       return wce;
-}
-
 /* Extended INQUIRY Data VPD Page */
 static sense_reason_t
 spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
@@ -490,7 +477,7 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
        buf[5] = 0x07;
 
        /* If WriteCache emulation is enabled, set V_SUP */
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                buf[6] = 0x01;
        /* If an LBA map is present set R_SUP */
        spin_lock(&cmd->se_dev->t10_alua.lba_map_lock);
@@ -897,7 +884,7 @@ static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p)
        if (pc == 1)
                goto out;
 
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                p[2] = 0x04; /* Write Cache Enable */
        p[12] = 0x20; /* Disabled Read Ahead */
 
@@ -1009,7 +996,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
             (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
                spc_modesense_write_protect(&buf[length], type);
 
-       if ((spc_check_dev_wce(dev)) &&
+       if ((se_dev_check_wce(dev)) &&
            (dev->dev_attrib.emulate_fua_write > 0))
                spc_modesense_dpofua(&buf[length], type);
 
index 0adc0f6..ac3cbab 100644 (file)
@@ -2389,6 +2389,10 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
        list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
 out:
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+       if (ret && ack_kref)
+               target_put_sess_cmd(se_sess, se_cmd);
+
        return ret;
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
index 97b486c..583e755 100644 (file)
@@ -359,7 +359,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                ep = fc_seq_exch(seq);
                if (ep) {
                        lport = ep->lp;
-                       if (lport && (ep->xid <= lport->lro_xid))
+                       if (lport && (ep->xid <= lport->lro_xid)) {
                                /*
                                 * "ddp_done" trigger invalidation of HW
                                 * specific DDP context
@@ -374,6 +374,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                                 * identified using ep->xid)
                                 */
                                cmd->was_ddp_setup = 0;
+                       }
                }
        }
 }
index 25d244c..031018e 100644 (file)
@@ -262,13 +262,12 @@ static int int3400_thermal_probe(struct platform_device *pdev)
        result = acpi_parse_art(priv->adev->handle, &priv->art_count,
                                &priv->arts, true);
        if (result)
-               goto free_priv;
-
+               dev_dbg(&pdev->dev, "_ART table parsing error\n");
 
        result = acpi_parse_trt(priv->adev->handle, &priv->trt_count,
                                &priv->trts, true);
        if (result)
-               goto free_art;
+               dev_dbg(&pdev->dev, "_TRT table parsing error\n");
 
        platform_set_drvdata(pdev, priv);
 
@@ -281,7 +280,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)
                                                &int3400_thermal_params, 0, 0);
        if (IS_ERR(priv->thermal)) {
                result = PTR_ERR(priv->thermal);
-               goto free_trt;
+               goto free_art_trt;
        }
 
        priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add(
@@ -295,9 +294,8 @@ static int int3400_thermal_probe(struct platform_device *pdev)
 
 free_zone:
        thermal_zone_device_unregister(priv->thermal);
-free_trt:
+free_art_trt:
        kfree(priv->trts);
-free_art:
        kfree(priv->arts);
 free_priv:
        kfree(priv);
index f88b088..1e25133 100644 (file)
@@ -208,7 +208,7 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
                                trip_cnt, GFP_KERNEL);
                if (!int34x_thermal_zone->aux_trips) {
                        ret = -ENOMEM;
-                       goto free_mem;
+                       goto err_trip_alloc;
                }
                trip_mask = BIT(trip_cnt) - 1;
                int34x_thermal_zone->aux_trip_nr = trip_cnt;
@@ -248,14 +248,15 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
                                                0, 0);
        if (IS_ERR(int34x_thermal_zone->zone)) {
                ret = PTR_ERR(int34x_thermal_zone->zone);
-               goto free_lpat;
+               goto err_thermal_zone;
        }
 
        return int34x_thermal_zone;
 
-free_lpat:
+err_thermal_zone:
        acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
-free_mem:
+       kfree(int34x_thermal_zone->aux_trips);
+err_trip_alloc:
        kfree(int34x_thermal_zone);
        return ERR_PTR(ret);
 }
@@ -266,6 +267,7 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone
 {
        thermal_zone_device_unregister(int34x_thermal_zone->zone);
        acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
+       kfree(int34x_thermal_zone->aux_trips);
        kfree(int34x_thermal_zone);
 }
 EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
index 6ceebd6..12623bc 100644 (file)
@@ -688,6 +688,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = {
        { X86_VENDOR_INTEL, 6, 0x45},
        { X86_VENDOR_INTEL, 6, 0x46},
        { X86_VENDOR_INTEL, 6, 0x4c},
+       { X86_VENDOR_INTEL, 6, 0x4d},
        { X86_VENDOR_INTEL, 6, 0x56},
        {}
 };
index 2580a48..fe4e767 100644 (file)
@@ -387,21 +387,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (irq) {
-               int ret;
-
                /*
                 * platform has IRQ support.
                 * Then, driver uses common registers
-                */
-
-               ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
-                                      dev_name(dev), common);
-               if (ret) {
-                       dev_err(dev, "irq request failed\n ");
-                       return ret;
-               }
-
-               /*
                 * rcar_has_irq_support() will be enabled
                 */
                res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
@@ -456,8 +444,16 @@ static int rcar_thermal_probe(struct platform_device *pdev)
        }
 
        /* enable temperature comparation */
-       if (irq)
+       if (irq) {
+               ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
+                                      dev_name(dev), common);
+               if (ret) {
+                       dev_err(dev, "irq request failed\n ");
+                       goto error_unregister;
+               }
+
                rcar_thermal_common_write(common, ENR, enr_bits);
+       }
 
        platform_set_drvdata(pdev, common);
 
@@ -467,9 +463,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 
 error_unregister:
        rcar_thermal_for_each_priv(priv, common) {
-               thermal_zone_device_unregister(priv->zone);
                if (rcar_has_irq_support(priv))
                        rcar_thermal_irq_disable(priv);
+               thermal_zone_device_unregister(priv->zone);
        }
 
        pm_runtime_put(dev);
@@ -485,9 +481,9 @@ static int rcar_thermal_remove(struct platform_device *pdev)
        struct rcar_thermal_priv *priv;
 
        rcar_thermal_for_each_priv(priv, common) {
-               thermal_zone_device_unregister(priv->zone);
                if (rcar_has_irq_support(priv))
                        rcar_thermal_irq_disable(priv);
+               thermal_zone_device_unregister(priv->zone);
        }
 
        pm_runtime_put(dev);
index 933cd80..1d30b09 100644 (file)
@@ -682,6 +682,7 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on)
 
        if (on) {
                con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
+               con |= (1 << EXYNOS7_PD_DET_EN_SHIFT);
                interrupt_en =
                        (of_thermal_is_trip_valid(tz, 7)
                        << EXYNOS7_TMU_INTEN_RISE7_SHIFT) |
@@ -704,9 +705,9 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on)
                        interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
        } else {
                con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
+               con &= ~(1 << EXYNOS7_PD_DET_EN_SHIFT);
                interrupt_en = 0; /* Disable all interrupts */
        }
-       con |= 1 << EXYNOS7_PD_DET_EN_SHIFT;
 
        writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN);
        writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
@@ -918,34 +919,16 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
 }
 
 static const struct of_device_id exynos_tmu_match[] = {
-       {
-               .compatible = "samsung,exynos3250-tmu",
-       },
-       {
-               .compatible = "samsung,exynos4210-tmu",
-       },
-       {
-               .compatible = "samsung,exynos4412-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5250-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5260-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5420-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5420-tmu-ext-triminfo",
-       },
-       {
-               .compatible = "samsung,exynos5440-tmu",
-       },
-       {
-               .compatible = "samsung,exynos7-tmu",
-       },
-       {},
+       { .compatible = "samsung,exynos3250-tmu", },
+       { .compatible = "samsung,exynos4210-tmu", },
+       { .compatible = "samsung,exynos4412-tmu", },
+       { .compatible = "samsung,exynos5250-tmu", },
+       { .compatible = "samsung,exynos5260-tmu", },
+       { .compatible = "samsung,exynos5420-tmu", },
+       { .compatible = "samsung,exynos5420-tmu-ext-triminfo", },
+       { .compatible = "samsung,exynos5440-tmu", },
+       { .compatible = "samsung,exynos7-tmu", },
+       { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, exynos_tmu_match);
 
index 48491d1..174d3bc 100644 (file)
@@ -899,6 +899,22 @@ thermal_cooling_device_trip_point_show(struct device *dev,
                return sprintf(buf, "%d\n", instance->trip);
 }
 
+static struct attribute *cooling_device_attrs[] = {
+       &dev_attr_cdev_type.attr,
+       &dev_attr_max_state.attr,
+       &dev_attr_cur_state.attr,
+       NULL,
+};
+
+static const struct attribute_group cooling_device_attr_group = {
+       .attrs = cooling_device_attrs,
+};
+
+static const struct attribute_group *cooling_device_attr_groups[] = {
+       &cooling_device_attr_group,
+       NULL,
+};
+
 /* Device management */
 
 /**
@@ -1130,6 +1146,7 @@ __thermal_cooling_device_register(struct device_node *np,
        cdev->ops = ops;
        cdev->updated = false;
        cdev->device.class = &thermal_class;
+       cdev->device.groups = cooling_device_attr_groups;
        cdev->devdata = devdata;
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
        result = device_register(&cdev->device);
@@ -1139,21 +1156,6 @@ __thermal_cooling_device_register(struct device_node *np,
                return ERR_PTR(result);
        }
 
-       /* sys I/F */
-       if (type) {
-               result = device_create_file(&cdev->device, &dev_attr_cdev_type);
-               if (result)
-                       goto unregister;
-       }
-
-       result = device_create_file(&cdev->device, &dev_attr_max_state);
-       if (result)
-               goto unregister;
-
-       result = device_create_file(&cdev->device, &dev_attr_cur_state);
-       if (result)
-               goto unregister;
-
        /* Add 'this' new cdev to the global cdev list */
        mutex_lock(&thermal_list_lock);
        list_add(&cdev->node, &thermal_cdev_list);
@@ -1163,11 +1165,6 @@ __thermal_cooling_device_register(struct device_node *np,
        bind_cdev(cdev);
 
        return cdev;
-
-unregister:
-       release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
-       device_unregister(&cdev->device);
-       return ERR_PTR(result);
 }
 
 /**
index 634b6ce..62a5d44 100644 (file)
@@ -1402,7 +1402,7 @@ int ti_bandgap_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
 {
        int i;
index 3fb054a..a38c175 100644 (file)
@@ -429,7 +429,7 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
 
        data = ti_bandgap_get_sensor_data(bgp, id);
 
-       if (data && data->cool_dev)
+       if (data)
                cpufreq_cooling_unregister(data->cool_dev);
 
        return 0;
index d7b198c..ce24182 100644 (file)
@@ -210,18 +210,6 @@ bfin_jc_chars_in_buffer(struct tty_struct *tty)
        return circ_cnt(&bfin_jc_write_buf);
 }
 
-static void
-bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       unsigned long expire = jiffies + timeout;
-       while (!circ_empty(&bfin_jc_write_buf)) {
-               if (signal_pending(current))
-                       break;
-               if (time_after(jiffies, expire))
-                       break;
-       }
-}
-
 static const struct tty_operations bfin_jc_ops = {
        .open            = bfin_jc_open,
        .close           = bfin_jc_close,
@@ -230,7 +218,6 @@ static const struct tty_operations bfin_jc_ops = {
        .flush_chars     = bfin_jc_flush_chars,
        .write_room      = bfin_jc_write_room,
        .chars_in_buffer = bfin_jc_chars_in_buffer,
-       .wait_until_sent = bfin_jc_wait_until_sent,
 };
 
 static int __init bfin_jc_init(void)
index e3b9570..deae122 100644 (file)
@@ -2138,8 +2138,8 @@ int serial8250_do_startup(struct uart_port *port)
        /*
         * Clear the interrupt registers.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_LSR);
+       serial_port_in(port, UART_RX);
        serial_port_in(port, UART_IIR);
        serial_port_in(port, UART_MSR);
 
@@ -2300,8 +2300,8 @@ dont_test_tx_en:
         * saved flags to avoid getting false values from polling
         * routines or the previous session.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_LSR);
+       serial_port_in(port, UART_RX);
        serial_port_in(port, UART_IIR);
        serial_port_in(port, UART_MSR);
        up->lsr_saved_flags = 0;
@@ -2394,8 +2394,7 @@ void serial8250_do_shutdown(struct uart_port *port)
         * Read data port to reset things, and then unlink from
         * the IRQ chain.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_RX);
        serial8250_rpm_put(up);
 
        del_timer_sync(&up->timer);
index e601162..6ae5b85 100644 (file)
@@ -59,6 +59,8 @@ struct dw8250_data {
        u8                      usr_reg;
        int                     last_mcr;
        int                     line;
+       int                     msr_mask_on;
+       int                     msr_mask_off;
        struct clk              *clk;
        struct clk              *pclk;
        struct reset_control    *rst;
@@ -81,6 +83,12 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
                value &= ~UART_MSR_DCTS;
        }
 
+       /* Override any modem control signals if needed */
+       if (offset == UART_MSR) {
+               value |= d->msr_mask_on;
+               value &= ~d->msr_mask_off;
+       }
+
        return value;
 }
 
@@ -111,7 +119,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
                        dw8250_force_idle(p);
                        writeb(value, p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 
@@ -155,7 +166,10 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
                        __raw_writeq(value & 0xff,
                                     p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 #endif /* CONFIG_64BIT */
@@ -179,7 +193,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
                        dw8250_force_idle(p);
                        writel(value, p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 
@@ -334,6 +351,30 @@ static int dw8250_probe_of(struct uart_port *p,
        if (id >= 0)
                p->line = id;
 
+       if (of_property_read_bool(np, "dcd-override")) {
+               /* Always report DCD as active */
+               data->msr_mask_on |= UART_MSR_DCD;
+               data->msr_mask_off |= UART_MSR_DDCD;
+       }
+
+       if (of_property_read_bool(np, "dsr-override")) {
+               /* Always report DSR as active */
+               data->msr_mask_on |= UART_MSR_DSR;
+               data->msr_mask_off |= UART_MSR_DDSR;
+       }
+
+       if (of_property_read_bool(np, "cts-override")) {
+               /* Always report DSR as active */
+               data->msr_mask_on |= UART_MSR_DSR;
+               data->msr_mask_off |= UART_MSR_DDSR;
+       }
+
+       if (of_property_read_bool(np, "ri-override")) {
+               /* Always report Ring indicator as inactive */
+               data->msr_mask_off |= UART_MSR_RI;
+               data->msr_mask_off |= UART_MSR_TERI;
+       }
+
        /* clock got configured through clk api, all done */
        if (p->uartclk)
                return 0;
index daf2c82..892eb32 100644 (file)
@@ -69,7 +69,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
               "Please send the output of lspci -vv, this\n"
               "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
               "manufacturer and name of serial board or\n"
-              "modem board to rmk+serial@arm.linux.org.uk.\n",
+              "modem board to <linux-serial@vger.kernel.org>.\n",
               pci_name(dev), str, dev->vendor, dev->device,
               dev->subsystem_vendor, dev->subsystem_device);
 }
@@ -1987,13 +1987,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = byt_serial_setup,
        },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_QRK_UART,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = PCI_DEVICE_ID_INTEL_BSW_UART1,
@@ -2199,13 +2192,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
        /*
         * PLX
         */
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9030,
-               .subvendor      = PCI_SUBVENDOR_ID_PERLE,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       },
        {
                .vendor         = PCI_VENDOR_ID_PLX,
                .device         = PCI_DEVICE_ID_PLX_9050,
@@ -5415,10 +5401,6 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_b0_bt_2_115200 },
 
-       {       PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0, 0, pbn_b0_bt_2_115200 },
-
        {       PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_wch384_4 },
index 846552b..4e959c4 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/err.h>
 #include <linux/irq.h>
+#include <linux/suspend.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -173,6 +174,12 @@ struct atmel_uart_port {
        bool                    ms_irq_enabled;
        bool                    is_usart;       /* usart or uart */
        struct timer_list       uart_timer;     /* uart timer */
+
+       bool                    suspended;
+       unsigned int            pending;
+       unsigned int            pending_status;
+       spinlock_t              lock_suspended;
+
        int (*prepare_rx)(struct uart_port *port);
        int (*prepare_tx)(struct uart_port *port);
        void (*schedule_rx)(struct uart_port *port);
@@ -1179,12 +1186,15 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status, pending, pass_counter = 0;
+       unsigned int status, pending, mask, pass_counter = 0;
        bool gpio_handled = false;
 
+       spin_lock(&atmel_port->lock_suspended);
+
        do {
                status = atmel_get_lines_status(port);
-               pending = status & UART_GET_IMR(port);
+               mask = UART_GET_IMR(port);
+               pending = status & mask;
                if (!gpio_handled) {
                        /*
                         * Dealing with GPIO interrupt
@@ -1206,11 +1216,21 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
                if (!pending)
                        break;
 
+               if (atmel_port->suspended) {
+                       atmel_port->pending |= pending;
+                       atmel_port->pending_status = status;
+                       UART_PUT_IDR(port, mask);
+                       pm_system_wakeup();
+                       break;
+               }
+
                atmel_handle_receive(port, pending);
                atmel_handle_status(port, pending, status);
                atmel_handle_transmit(port, pending);
        } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
 
+       spin_unlock(&atmel_port->lock_suspended);
+
        return pass_counter ? IRQ_HANDLED : IRQ_NONE;
 }
 
@@ -1742,7 +1762,8 @@ static int atmel_startup(struct uart_port *port)
        /*
         * Allocate the IRQ
         */
-       retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
+       retval = request_irq(port->irq, atmel_interrupt,
+                       IRQF_SHARED | IRQF_COND_SUSPEND,
                        tty ? tty->name : "atmel_serial", port);
        if (retval) {
                dev_err(port->dev, "atmel_startup - Can't get irq\n");
@@ -2513,8 +2534,14 @@ static int atmel_serial_suspend(struct platform_device *pdev,
 
        /* we can not wake up if we're running on slow clock */
        atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
-       if (atmel_serial_clk_will_stop())
+       if (atmel_serial_clk_will_stop()) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&atmel_port->lock_suspended, flags);
+               atmel_port->suspended = true;
+               spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
                device_set_wakeup_enable(&pdev->dev, 0);
+       }
 
        uart_suspend_port(&atmel_uart, port);
 
@@ -2525,6 +2552,18 @@ static int atmel_serial_resume(struct platform_device *pdev)
 {
        struct uart_port *port = platform_get_drvdata(pdev);
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&atmel_port->lock_suspended, flags);
+       if (atmel_port->pending) {
+               atmel_handle_receive(port, atmel_port->pending);
+               atmel_handle_status(port, atmel_port->pending,
+                                   atmel_port->pending_status);
+               atmel_handle_transmit(port, atmel_port->pending);
+               atmel_port->pending = 0;
+       }
+       atmel_port->suspended = false;
+       spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
 
        uart_resume_port(&atmel_uart, port);
        device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
@@ -2593,6 +2632,8 @@ static int atmel_serial_probe(struct platform_device *pdev)
        port->backup_imr = 0;
        port->uart.line = ret;
 
+       spin_lock_init(&port->lock_suspended);
+
        ret = atmel_init_gpios(port, &pdev->dev);
        if (ret < 0)
                dev_err(&pdev->dev, "%s",
index b1893f3..3ad1458 100644 (file)
@@ -921,6 +921,9 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
        writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
                        sport->port.membase + UARTPFIFO);
 
+       /* explicitly clear RDRF */
+       readb(sport->port.membase + UARTSR1);
+
        /* flush Tx and Rx FIFO */
        writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
                        sport->port.membase + UARTCFIFO);
@@ -1076,6 +1079,8 @@ static int lpuart_startup(struct uart_port *port)
        sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) &
                UARTPFIFO_FIFOSIZE_MASK) + 1);
 
+       sport->port.fifosize = sport->txfifo_size;
+
        sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
                UARTPFIFO_FIFOSIZE_MASK) + 1);
 
index 7ff61e2..33fb94f 100644 (file)
@@ -133,10 +133,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
        if (of_find_property(np, "no-loopback-test", NULL))
                port->flags |= UPF_SKIP_TEST;
 
-       ret = of_alias_get_id(np, "serial");
-       if (ret >= 0)
-               port->line = ret;
-
        port->dev = &ofdev->dev;
 
        switch (type) {
index af821a9..cf08876 100644 (file)
@@ -963,6 +963,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
                        free_irq(ourport->tx_irq, ourport);
                tx_enabled(port) = 0;
                ourport->tx_claimed = 0;
+               ourport->tx_mode = 0;
        }
 
        if (ourport->rx_claimed) {
index 594b633..bca975f 100644 (file)
@@ -293,8 +293,10 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
 
        ims = serial_in(port, SPRD_IMSR);
 
-       if (!ims)
+       if (!ims) {
+               spin_unlock(&port->lock);
                return IRQ_NONE;
+       }
 
        serial_out(port, SPRD_ICLR, ~0);
 
index 51f066a..2bb4dfc 100644 (file)
@@ -1028,8 +1028,8 @@ EXPORT_SYMBOL(start_tty);
 /* We limit tty time update visibility to every 8 seconds or so. */
 static void tty_update_time(struct timespec *time)
 {
-       unsigned long sec = get_seconds() & ~7;
-       if ((long)(sec - time->tv_sec) > 0)
+       unsigned long sec = get_seconds();
+       if (abs(sec - time->tv_sec) & ~7)
                time->tv_sec = sec;
 }
 
index a5cf253..632fc81 100644 (file)
@@ -217,11 +217,17 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
 #endif
        if (!timeout)
                timeout = MAX_SCHEDULE_TIMEOUT;
-       if (wait_event_interruptible_timeout(tty->write_wait,
-                       !tty_chars_in_buffer(tty), timeout) >= 0) {
-               if (tty->ops->wait_until_sent)
-                       tty->ops->wait_until_sent(tty, timeout);
-       }
+
+       timeout = wait_event_interruptible_timeout(tty->write_wait,
+                       !tty_chars_in_buffer(tty), timeout);
+       if (timeout <= 0)
+               return;
+
+       if (timeout == MAX_SCHEDULE_TIMEOUT)
+               timeout = 0;
+
+       if (tty->ops->wait_until_sent)
+               tty->ops->wait_until_sent(tty, timeout);
 }
 EXPORT_SYMBOL(tty_wait_until_sent);
 
index ff45104..4bfb7ac 100644 (file)
@@ -929,6 +929,13 @@ __acquires(hwep->lock)
        return retval;
 }
 
+static int otg_a_alt_hnp_support(struct ci_hdrc *ci)
+{
+       dev_warn(&ci->gadget.dev,
+               "connect the device to an alternate port if you want HNP\n");
+       return isr_setup_status_phase(ci);
+}
+
 /**
  * isr_setup_packet_handler: setup packet handler
  * @ci: UDC descriptor
@@ -1061,6 +1068,10 @@ __acquires(ci->lock)
                                                        ci);
                                }
                                break;
+                       case USB_DEVICE_A_ALT_HNP_SUPPORT:
+                               if (ci_otg_is_fsm_mode(ci))
+                                       err = otg_a_alt_hnp_support(ci);
+                               break;
                        default:
                                goto delegate;
                        }
index e78720b..6836177 100644 (file)
@@ -1650,6 +1650,8 @@ static int acm_reset_resume(struct usb_interface *intf)
 
 static const struct usb_device_id acm_ids[] = {
        /* quirky and broken devices */
+       { USB_DEVICE(0x076d, 0x0006), /* Denso Cradle CU-321 */
+       .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
        { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
        .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
        { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
index c6b35b7..61d538a 100644 (file)
@@ -150,9 +150,9 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
                break;
        case OTG_STATE_B_PERIPHERAL:
                otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 1);
                otg_loc_sof(fsm, 0);
                otg_set_protocol(fsm, PROTO_GADGET);
+               otg_loc_conn(fsm, 1);
                break;
        case OTG_STATE_B_WAIT_ACON:
                otg_chrg_vbus(fsm, 0);
@@ -213,10 +213,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 
                break;
        case OTG_STATE_A_PERIPHERAL:
-               otg_loc_conn(fsm, 1);
                otg_loc_sof(fsm, 0);
                otg_set_protocol(fsm, PROTO_GADGET);
                otg_drv_vbus(fsm, 1);
+               otg_loc_conn(fsm, 1);
                otg_add_timer(fsm, A_BIDL_ADIS);
                break;
        case OTG_STATE_A_WAIT_VFALL:
index 66abdbc..1163553 100644 (file)
@@ -501,6 +501,7 @@ static void async_completed(struct urb *urb)
        as->status = urb->status;
        signr = as->signr;
        if (signr) {
+               memset(&sinfo, 0, sizeof(sinfo));
                sinfo.si_signo = as->signr;
                sinfo.si_errno = as->status;
                sinfo.si_code = SI_ASYNCIO;
@@ -2382,6 +2383,7 @@ static void usbdev_remove(struct usb_device *udev)
                wake_up_all(&ps->wait);
                list_del_init(&ps->list);
                if (ps->discsignr) {
+                       memset(&sinfo, 0, sizeof(sinfo));
                        sinfo.si_signo = ps->discsignr;
                        sinfo.si_errno = EPIPE;
                        sinfo.si_code = SI_ASYNCIO;
index 02e3e2d..6cf0478 100644 (file)
@@ -377,6 +377,9 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
                dwc2_is_host_mode(hsotg) ? "Host" : "Device",
                dwc2_op_state_str(hsotg));
 
+       if (hsotg->op_state == OTG_STATE_A_HOST)
+               dwc2_hcd_disconnect(hsotg);
+
        /* Change to L3 (OFF) state */
        hsotg->lx_state = DWC2_L3;
 
index 172d64e..52e0c4e 100644 (file)
@@ -205,6 +205,18 @@ static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value)
                                                omap->irq0_offset, value);
 }
 
+static void dwc3_omap_write_irqmisc_clr(struct dwc3_omap *omap, u32 value)
+{
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_MISC +
+                                               omap->irqmisc_offset, value);
+}
+
+static void dwc3_omap_write_irq0_clr(struct dwc3_omap *omap, u32 value)
+{
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_0 -
+                                               omap->irq0_offset, value);
+}
+
 static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
        enum omap_dwc3_vbus_id_status status)
 {
@@ -345,9 +357,23 @@ static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
 
 static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
 {
+       u32                     reg;
+
        /* disable all IRQs */
-       dwc3_omap_write_irqmisc_set(omap, 0x00);
-       dwc3_omap_write_irq0_set(omap, 0x00);
+       reg = USBOTGSS_IRQO_COREIRQ_ST;
+       dwc3_omap_write_irq0_clr(omap, reg);
+
+       reg = (USBOTGSS_IRQMISC_OEVT |
+                       USBOTGSS_IRQMISC_DRVVBUS_RISE |
+                       USBOTGSS_IRQMISC_CHRGVBUS_RISE |
+                       USBOTGSS_IRQMISC_DISCHRGVBUS_RISE |
+                       USBOTGSS_IRQMISC_IDPULLUP_RISE |
+                       USBOTGSS_IRQMISC_DRVVBUS_FALL |
+                       USBOTGSS_IRQMISC_CHRGVBUS_FALL |
+                       USBOTGSS_IRQMISC_DISCHRGVBUS_FALL |
+                       USBOTGSS_IRQMISC_IDPULLUP_FALL);
+
+       dwc3_omap_write_irqmisc_clr(omap, reg);
 }
 
 static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
index 7564814..c42765b 100644 (file)
@@ -1161,7 +1161,6 @@ static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc,
        if (desc->opts_mutex)
                mutex_lock(desc->opts_mutex);
        memcpy(desc->ext_compat_id, page, l);
-       desc->ext_compat_id[l] = '\0';
 
        if (desc->opts_mutex)
                mutex_unlock(desc->opts_mutex);
@@ -1192,7 +1191,6 @@ static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc,
        if (desc->opts_mutex)
                mutex_lock(desc->opts_mutex);
        memcpy(desc->ext_compat_id + 8, page, l);
-       desc->ext_compat_id[l + 8] = '\0';
 
        if (desc->opts_mutex)
                mutex_unlock(desc->opts_mutex);
index af98b09..175c995 100644 (file)
@@ -144,10 +144,9 @@ struct ffs_io_data {
        bool read;
 
        struct kiocb *kiocb;
-       const struct iovec *iovec;
-       unsigned long nr_segs;
-       char __user *buf;
-       size_t len;
+       struct iov_iter data;
+       const void *to_free;
+       char *buf;
 
        struct mm_struct *mm;
        struct work_struct work;
@@ -649,29 +648,10 @@ static void ffs_user_copy_worker(struct work_struct *work)
                                         io_data->req->actual;
 
        if (io_data->read && ret > 0) {
-               int i;
-               size_t pos = 0;
-
-               /*
-                * Since req->length may be bigger than io_data->len (after
-                * being rounded up to maxpacketsize), we may end up with more
-                * data then user space has space for.
-                */
-               ret = min_t(int, ret, io_data->len);
-
                use_mm(io_data->mm);
-               for (i = 0; i < io_data->nr_segs; i++) {
-                       size_t len = min_t(size_t, ret - pos,
-                                       io_data->iovec[i].iov_len);
-                       if (!len)
-                               break;
-                       if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
-                                                &io_data->buf[pos], len))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       pos += len;
-               }
+               ret = copy_to_iter(io_data->buf, ret, &io_data->data);
+               if (iov_iter_count(&io_data->data))
+                       ret = -EFAULT;
                unuse_mm(io_data->mm);
        }
 
@@ -684,7 +664,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
 
        io_data->kiocb->private = NULL;
        if (io_data->read)
-               kfree(io_data->iovec);
+               kfree(io_data->to_free);
        kfree(io_data->buf);
        kfree(io_data);
 }
@@ -743,6 +723,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                 * before the waiting completes, so do not assign to 'gadget' earlier
                 */
                struct usb_gadget *gadget = epfile->ffs->gadget;
+               size_t copied;
 
                spin_lock_irq(&epfile->ffs->eps_lock);
                /* In the meantime, endpoint got disabled or changed. */
@@ -750,34 +731,21 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                        spin_unlock_irq(&epfile->ffs->eps_lock);
                        return -ESHUTDOWN;
                }
+               data_len = iov_iter_count(&io_data->data);
                /*
                 * Controller may require buffer size to be aligned to
                 * maxpacketsize of an out endpoint.
                 */
-               data_len = io_data->read ?
-                          usb_ep_align_maybe(gadget, ep->ep, io_data->len) :
-                          io_data->len;
+               if (io_data->read)
+                       data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
                spin_unlock_irq(&epfile->ffs->eps_lock);
 
                data = kmalloc(data_len, GFP_KERNEL);
                if (unlikely(!data))
                        return -ENOMEM;
-               if (io_data->aio && !io_data->read) {
-                       int i;
-                       size_t pos = 0;
-                       for (i = 0; i < io_data->nr_segs; i++) {
-                               if (unlikely(copy_from_user(&data[pos],
-                                            io_data->iovec[i].iov_base,
-                                            io_data->iovec[i].iov_len))) {
-                                       ret = -EFAULT;
-                                       goto error;
-                               }
-                               pos += io_data->iovec[i].iov_len;
-                       }
-               } else {
-                       if (!io_data->read &&
-                           unlikely(__copy_from_user(data, io_data->buf,
-                                                     io_data->len))) {
+               if (!io_data->read) {
+                       copied = copy_from_iter(data, data_len, &io_data->data);
+                       if (copied != data_len) {
                                ret = -EFAULT;
                                goto error;
                        }
@@ -876,10 +844,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                                 */
                                ret = ep->status;
                                if (io_data->read && ret > 0) {
-                                       ret = min_t(size_t, ret, io_data->len);
-
-                                       if (unlikely(copy_to_user(io_data->buf,
-                                               data, ret)))
+                                       ret = copy_to_iter(data, ret, &io_data->data);
+                                       if (unlikely(iov_iter_count(&io_data->data)))
                                                ret = -EFAULT;
                                }
                        }
@@ -898,37 +864,6 @@ error:
        return ret;
 }
 
-static ssize_t
-ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
-                loff_t *ptr)
-{
-       struct ffs_io_data io_data;
-
-       ENTER();
-
-       io_data.aio = false;
-       io_data.read = false;
-       io_data.buf = (char * __user)buf;
-       io_data.len = len;
-
-       return ffs_epfile_io(file, &io_data);
-}
-
-static ssize_t
-ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ffs_io_data io_data;
-
-       ENTER();
-
-       io_data.aio = false;
-       io_data.read = true;
-       io_data.buf = buf;
-       io_data.len = len;
-
-       return ffs_epfile_io(file, &io_data);
-}
-
 static int
 ffs_epfile_open(struct inode *inode, struct file *file)
 {
@@ -965,67 +900,86 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
        return value;
 }
 
-static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb,
-                                   const struct iovec *iovec,
-                                   unsigned long nr_segs, loff_t loff)
+static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 {
-       struct ffs_io_data *io_data;
+       struct ffs_io_data io_data, *p = &io_data;
+       ssize_t res;
 
        ENTER();
 
-       io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
-       if (unlikely(!io_data))
-               return -ENOMEM;
+       if (!is_sync_kiocb(kiocb)) {
+               p = kmalloc(sizeof(io_data), GFP_KERNEL);
+               if (unlikely(!p))
+                       return -ENOMEM;
+               p->aio = true;
+       } else {
+               p->aio = false;
+       }
 
-       io_data->aio = true;
-       io_data->read = false;
-       io_data->kiocb = kiocb;
-       io_data->iovec = iovec;
-       io_data->nr_segs = nr_segs;
-       io_data->len = kiocb->ki_nbytes;
-       io_data->mm = current->mm;
+       p->read = false;
+       p->kiocb = kiocb;
+       p->data = *from;
+       p->mm = current->mm;
 
-       kiocb->private = io_data;
+       kiocb->private = p;
 
        kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
-       return ffs_epfile_io(kiocb->ki_filp, io_data);
+       res = ffs_epfile_io(kiocb->ki_filp, p);
+       if (res == -EIOCBQUEUED)
+               return res;
+       if (p->aio)
+               kfree(p);
+       else
+               *from = p->data;
+       return res;
 }
 
-static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb,
-                                  const struct iovec *iovec,
-                                  unsigned long nr_segs, loff_t loff)
+static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 {
-       struct ffs_io_data *io_data;
-       struct iovec *iovec_copy;
+       struct ffs_io_data io_data, *p = &io_data;
+       ssize_t res;
 
        ENTER();
 
-       iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL);
-       if (unlikely(!iovec_copy))
-               return -ENOMEM;
-
-       memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs);
-
-       io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
-       if (unlikely(!io_data)) {
-               kfree(iovec_copy);
-               return -ENOMEM;
+       if (!is_sync_kiocb(kiocb)) {
+               p = kmalloc(sizeof(io_data), GFP_KERNEL);
+               if (unlikely(!p))
+                       return -ENOMEM;
+               p->aio = true;
+       } else {
+               p->aio = false;
        }
 
-       io_data->aio = true;
-       io_data->read = true;
-       io_data->kiocb = kiocb;
-       io_data->iovec = iovec_copy;
-       io_data->nr_segs = nr_segs;
-       io_data->len = kiocb->ki_nbytes;
-       io_data->mm = current->mm;
+       p->read = true;
+       p->kiocb = kiocb;
+       if (p->aio) {
+               p->to_free = dup_iter(&p->data, to, GFP_KERNEL);
+               if (!p->to_free) {
+                       kfree(p);
+                       return -ENOMEM;
+               }
+       } else {
+               p->data = *to;
+               p->to_free = NULL;
+       }
+       p->mm = current->mm;
 
-       kiocb->private = io_data;
+       kiocb->private = p;
 
        kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
-       return ffs_epfile_io(kiocb->ki_filp, io_data);
+       res = ffs_epfile_io(kiocb->ki_filp, p);
+       if (res == -EIOCBQUEUED)
+               return res;
+
+       if (p->aio) {
+               kfree(p->to_free);
+               kfree(p);
+       } else {
+               *to = p->data;
+       }
+       return res;
 }
 
 static int
@@ -1105,10 +1059,10 @@ static const struct file_operations ffs_epfile_operations = {
        .llseek =       no_llseek,
 
        .open =         ffs_epfile_open,
-       .write =        ffs_epfile_write,
-       .read =         ffs_epfile_read,
-       .aio_write =    ffs_epfile_aio_write,
-       .aio_read =     ffs_epfile_aio_read,
+       .write =        new_sync_write,
+       .read =         new_sync_read,
+       .write_iter =   ffs_epfile_write_iter,
+       .read_iter =    ffs_epfile_read_iter,
        .release =      ffs_epfile_release,
        .unlocked_ioctl =       ffs_epfile_ioctl,
 };
index 426d69a..a2612fb 100644 (file)
@@ -569,7 +569,7 @@ fail:
        return status;
 }
 
-const struct file_operations f_hidg_fops = {
+static const struct file_operations f_hidg_fops = {
        .owner          = THIS_MODULE,
        .open           = f_hidg_open,
        .release        = f_hidg_release,
index 298b461..39f49f1 100644 (file)
@@ -289,8 +289,7 @@ static void disable_loopback(struct f_loopback *loop)
        struct usb_composite_dev        *cdev;
 
        cdev = loop->function.config->cdev;
-       disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL, NULL,
-                       NULL);
+       disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
        VDBG(cdev, "%s disabled\n", loop->function.name);
 }
 
index c89e96c..c0c3ef2 100644 (file)
@@ -417,7 +417,10 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        return -EINVAL;
 
                spin_lock(&port->lock);
-               __pn_reset(f);
+
+               if (fp->in_ep->driver_data)
+                       __pn_reset(f);
+
                if (alt == 1) {
                        int i;
 
index e07c50c..3a5ae99 100644 (file)
 #include "gadget_chips.h"
 #include "u_f.h"
 
-#define USB_MS_TO_SS_INTERVAL(x) USB_MS_TO_HS_INTERVAL(x)
-
-enum eptype {
-       EP_CONTROL = 0,
-       EP_BULK,
-       EP_ISOC,
-       EP_INTERRUPT,
-};
-
 /*
  * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
  * controller drivers.
@@ -64,8 +55,6 @@ struct f_sourcesink {
        struct usb_ep           *out_ep;
        struct usb_ep           *iso_in_ep;
        struct usb_ep           *iso_out_ep;
-       struct usb_ep           *int_in_ep;
-       struct usb_ep           *int_out_ep;
        int                     cur_alt;
 };
 
@@ -79,10 +68,6 @@ static unsigned isoc_interval;
 static unsigned isoc_maxpacket;
 static unsigned isoc_mult;
 static unsigned isoc_maxburst;
-static unsigned int_interval; /* In ms */
-static unsigned int_maxpacket;
-static unsigned int_mult;
-static unsigned int_maxburst;
 static unsigned buflen;
 
 /*-------------------------------------------------------------------------*/
@@ -107,16 +92,6 @@ static struct usb_interface_descriptor source_sink_intf_alt1 = {
        /* .iInterface          = DYNAMIC */
 };
 
-static struct usb_interface_descriptor source_sink_intf_alt2 = {
-       .bLength =              USB_DT_INTERFACE_SIZE,
-       .bDescriptorType =      USB_DT_INTERFACE,
-
-       .bAlternateSetting =    2,
-       .bNumEndpoints =        2,
-       .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
-       /* .iInterface          = DYNAMIC */
-};
-
 /* full speed support: */
 
 static struct usb_endpoint_descriptor fs_source_desc = {
@@ -155,26 +130,6 @@ static struct usb_endpoint_descriptor fs_iso_sink_desc = {
        .bInterval =            4,
 };
 
-static struct usb_endpoint_descriptor fs_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(64),
-       .bInterval =            GZERO_INT_INTERVAL,
-};
-
-static struct usb_endpoint_descriptor fs_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(64),
-       .bInterval =            GZERO_INT_INTERVAL,
-};
-
 static struct usb_descriptor_header *fs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &fs_sink_desc,
@@ -185,10 +140,6 @@ static struct usb_descriptor_header *fs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &fs_source_desc,
        (struct usb_descriptor_header *) &fs_iso_sink_desc,
        (struct usb_descriptor_header *) &fs_iso_source_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define FS_ALT_IFC_2_OFFSET    8
-       (struct usb_descriptor_header *) &fs_int_sink_desc,
-       (struct usb_descriptor_header *) &fs_int_source_desc,
        NULL,
 };
 
@@ -228,24 +179,6 @@ static struct usb_endpoint_descriptor hs_iso_sink_desc = {
        .bInterval =            4,
 };
 
-static struct usb_endpoint_descriptor hs_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-static struct usb_endpoint_descriptor hs_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
 static struct usb_descriptor_header *hs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &hs_source_desc,
@@ -256,10 +189,6 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &hs_sink_desc,
        (struct usb_descriptor_header *) &hs_iso_source_desc,
        (struct usb_descriptor_header *) &hs_iso_sink_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define HS_ALT_IFC_2_OFFSET    8
-       (struct usb_descriptor_header *) &hs_int_source_desc,
-       (struct usb_descriptor_header *) &hs_int_sink_desc,
        NULL,
 };
 
@@ -335,42 +264,6 @@ static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
        .wBytesPerInterval =    cpu_to_le16(1024),
 };
 
-static struct usb_endpoint_descriptor ss_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-struct usb_ss_ep_comp_descriptor ss_int_source_comp_desc = {
-       .bLength =              USB_DT_SS_EP_COMP_SIZE,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       .bMaxBurst =            0,
-       .bmAttributes =         0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
-};
-
-static struct usb_endpoint_descriptor ss_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-struct usb_ss_ep_comp_descriptor ss_int_sink_comp_desc = {
-       .bLength =              USB_DT_SS_EP_COMP_SIZE,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       .bMaxBurst =            0,
-       .bmAttributes =         0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
-};
-
 static struct usb_descriptor_header *ss_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &ss_source_desc,
@@ -387,12 +280,6 @@ static struct usb_descriptor_header *ss_source_sink_descs[] = {
        (struct usb_descriptor_header *) &ss_iso_source_comp_desc,
        (struct usb_descriptor_header *) &ss_iso_sink_desc,
        (struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define SS_ALT_IFC_2_OFFSET    14
-       (struct usb_descriptor_header *) &ss_int_source_desc,
-       (struct usb_descriptor_header *) &ss_int_source_comp_desc,
-       (struct usb_descriptor_header *) &ss_int_sink_desc,
-       (struct usb_descriptor_header *) &ss_int_sink_comp_desc,
        NULL,
 };
 
@@ -414,21 +301,6 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
 };
 
 /*-------------------------------------------------------------------------*/
-static const char *get_ep_string(enum eptype ep_type)
-{
-       switch (ep_type) {
-       case EP_ISOC:
-               return "ISOC-";
-       case EP_INTERRUPT:
-               return "INTERRUPT-";
-       case EP_CONTROL:
-               return "CTRL-";
-       case EP_BULK:
-               return "BULK-";
-       default:
-               return "UNKNOWN-";
-       }
-}
 
 static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
 {
@@ -456,8 +328,7 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
 
 void disable_endpoints(struct usb_composite_dev *cdev,
                struct usb_ep *in, struct usb_ep *out,
-               struct usb_ep *iso_in, struct usb_ep *iso_out,
-               struct usb_ep *int_in, struct usb_ep *int_out)
+               struct usb_ep *iso_in, struct usb_ep *iso_out)
 {
        disable_ep(cdev, in);
        disable_ep(cdev, out);
@@ -465,10 +336,6 @@ void disable_endpoints(struct usb_composite_dev *cdev,
                disable_ep(cdev, iso_in);
        if (iso_out)
                disable_ep(cdev, iso_out);
-       if (int_in)
-               disable_ep(cdev, int_in);
-       if (int_out)
-               disable_ep(cdev, int_out);
 }
 
 static int
@@ -485,7 +352,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
                return id;
        source_sink_intf_alt0.bInterfaceNumber = id;
        source_sink_intf_alt1.bInterfaceNumber = id;
-       source_sink_intf_alt2.bInterfaceNumber = id;
 
        /* allocate bulk endpoints */
        ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
@@ -546,55 +412,14 @@ no_iso:
        if (isoc_maxpacket > 1024)
                isoc_maxpacket = 1024;
 
-       /* sanity check the interrupt module parameters */
-       if (int_interval < 1)
-               int_interval = 1;
-       if (int_interval > 4096)
-               int_interval = 4096;
-       if (int_mult > 2)
-               int_mult = 2;
-       if (int_maxburst > 15)
-               int_maxburst = 15;
-
-       /* fill in the FS interrupt descriptors from the module parameters */
-       fs_int_source_desc.wMaxPacketSize = int_maxpacket > 64 ?
-                                               64 : int_maxpacket;
-       fs_int_source_desc.bInterval = int_interval > 255 ?
-                                               255 : int_interval;
-       fs_int_sink_desc.wMaxPacketSize = int_maxpacket > 64 ?
-                                               64 : int_maxpacket;
-       fs_int_sink_desc.bInterval = int_interval > 255 ?
-                                               255 : int_interval;
-
-       /* allocate int endpoints */
-       ss->int_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_source_desc);
-       if (!ss->int_in_ep)
-               goto no_int;
-       ss->int_in_ep->driver_data = cdev;      /* claim */
-
-       ss->int_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_sink_desc);
-       if (ss->int_out_ep) {
-               ss->int_out_ep->driver_data = cdev;     /* claim */
-       } else {
-               ss->int_in_ep->driver_data = NULL;
-               ss->int_in_ep = NULL;
-no_int:
-               fs_source_sink_descs[FS_ALT_IFC_2_OFFSET] = NULL;
-               hs_source_sink_descs[HS_ALT_IFC_2_OFFSET] = NULL;
-               ss_source_sink_descs[SS_ALT_IFC_2_OFFSET] = NULL;
-       }
-
-       if (int_maxpacket > 1024)
-               int_maxpacket = 1024;
-
        /* support high speed hardware */
        hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
        hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 
        /*
-        * Fill in the HS isoc and interrupt descriptors from the module
-        * parameters. We assume that the user knows what they are doing and
-        * won't give parameters that their UDC doesn't support.
+        * Fill in the HS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
         */
        hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
        hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
@@ -607,17 +432,6 @@ no_int:
        hs_iso_sink_desc.bInterval = isoc_interval;
        hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
-       hs_int_source_desc.wMaxPacketSize = int_maxpacket;
-       hs_int_source_desc.wMaxPacketSize |= int_mult << 11;
-       hs_int_source_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
-       hs_int_source_desc.bEndpointAddress =
-               fs_int_source_desc.bEndpointAddress;
-
-       hs_int_sink_desc.wMaxPacketSize = int_maxpacket;
-       hs_int_sink_desc.wMaxPacketSize |= int_mult << 11;
-       hs_int_sink_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
-       hs_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
-
        /* support super speed hardware */
        ss_source_desc.bEndpointAddress =
                fs_source_desc.bEndpointAddress;
@@ -625,9 +439,9 @@ no_int:
                fs_sink_desc.bEndpointAddress;
 
        /*
-        * Fill in the SS isoc and interrupt descriptors from the module
-        * parameters. We assume that the user knows what they are doing and
-        * won't give parameters that their UDC doesn't support.
+        * Fill in the SS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
         */
        ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
        ss_iso_source_desc.bInterval = isoc_interval;
@@ -646,37 +460,17 @@ no_int:
                isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
        ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
-       ss_int_source_desc.wMaxPacketSize = int_maxpacket;
-       ss_int_source_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
-       ss_int_source_comp_desc.bmAttributes = int_mult;
-       ss_int_source_comp_desc.bMaxBurst = int_maxburst;
-       ss_int_source_comp_desc.wBytesPerInterval =
-               int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
-       ss_int_source_desc.bEndpointAddress =
-               fs_int_source_desc.bEndpointAddress;
-
-       ss_int_sink_desc.wMaxPacketSize = int_maxpacket;
-       ss_int_sink_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
-       ss_int_sink_comp_desc.bmAttributes = int_mult;
-       ss_int_sink_comp_desc.bMaxBurst = int_maxburst;
-       ss_int_sink_comp_desc.wBytesPerInterval =
-               int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
-       ss_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
-
        ret = usb_assign_descriptors(f, fs_source_sink_descs,
                        hs_source_sink_descs, ss_source_sink_descs);
        if (ret)
                return ret;
 
-       DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s, "
-                       "INT-IN/%s, INT-OUT/%s\n",
+       DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
             (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
                        f->name, ss->in_ep->name, ss->out_ep->name,
                        ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
-                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>",
-                       ss->int_in_ep ? ss->int_in_ep->name : "<none>",
-                       ss->int_out_ep ? ss->int_out_ep->name : "<none>");
+                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
        return 0;
 }
 
@@ -807,15 +601,14 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 }
 
 static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
-               enum eptype ep_type, int speed)
+               bool is_iso, int speed)
 {
        struct usb_ep           *ep;
        struct usb_request      *req;
        int                     i, size, status;
 
        for (i = 0; i < 8; i++) {
-               switch (ep_type) {
-               case EP_ISOC:
+               if (is_iso) {
                        switch (speed) {
                        case USB_SPEED_SUPER:
                                size = isoc_maxpacket * (isoc_mult + 1) *
@@ -831,28 +624,9 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
                        }
                        ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
                        req = ss_alloc_ep_req(ep, size);
-                       break;
-               case EP_INTERRUPT:
-                       switch (speed) {
-                       case USB_SPEED_SUPER:
-                               size = int_maxpacket * (int_mult + 1) *
-                                               (int_maxburst + 1);
-                               break;
-                       case USB_SPEED_HIGH:
-                               size = int_maxpacket * (int_mult + 1);
-                               break;
-                       default:
-                               size = int_maxpacket > 1023 ?
-                                               1023 : int_maxpacket;
-                               break;
-                       }
-                       ep = is_in ? ss->int_in_ep : ss->int_out_ep;
-                       req = ss_alloc_ep_req(ep, size);
-                       break;
-               default:
+               } else {
                        ep = is_in ? ss->in_ep : ss->out_ep;
                        req = ss_alloc_ep_req(ep, 0);
-                       break;
                }
 
                if (!req)
@@ -870,12 +644,12 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 
                        cdev = ss->function.config->cdev;
                        ERROR(cdev, "start %s%s %s --> %d\n",
-                               get_ep_string(ep_type), is_in ? "IN" : "OUT",
-                               ep->name, status);
+                             is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
+                             ep->name, status);
                        free_ep_req(ep, req);
                }
 
-               if (!(ep_type == EP_ISOC))
+               if (!is_iso)
                        break;
        }
 
@@ -888,7 +662,7 @@ static void disable_source_sink(struct f_sourcesink *ss)
 
        cdev = ss->function.config->cdev;
        disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
-                       ss->iso_out_ep, ss->int_in_ep, ss->int_out_ep);
+                       ss->iso_out_ep);
        VDBG(cdev, "%s disabled\n", ss->function.name);
 }
 
@@ -900,62 +674,6 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
        int                                     speed = cdev->gadget->speed;
        struct usb_ep                           *ep;
 
-       if (alt == 2) {
-               /* Configure for periodic interrupt endpoint */
-               ep = ss->int_in_ep;
-               if (ep) {
-                       result = config_ep_by_speed(cdev->gadget,
-                                       &(ss->function), ep);
-                       if (result)
-                               return result;
-
-                       result = usb_ep_enable(ep);
-                       if (result < 0)
-                               return result;
-
-                       ep->driver_data = ss;
-                       result = source_sink_start_ep(ss, true, EP_INTERRUPT,
-                                       speed);
-                       if (result < 0) {
-fail1:
-                               ep = ss->int_in_ep;
-                               if (ep) {
-                                       usb_ep_disable(ep);
-                                       ep->driver_data = NULL;
-                               }
-                               return result;
-                       }
-               }
-
-               /*
-                * one interrupt endpoint reads (sinks) anything OUT (from the
-                * host)
-                */
-               ep = ss->int_out_ep;
-               if (ep) {
-                       result = config_ep_by_speed(cdev->gadget,
-                                       &(ss->function), ep);
-                       if (result)
-                               goto fail1;
-
-                       result = usb_ep_enable(ep);
-                       if (result < 0)
-                               goto fail1;
-
-                       ep->driver_data = ss;
-                       result = source_sink_start_ep(ss, false, EP_INTERRUPT,
-                                       speed);
-                       if (result < 0) {
-                               ep = ss->int_out_ep;
-                               usb_ep_disable(ep);
-                               ep->driver_data = NULL;
-                               goto fail1;
-                       }
-               }
-
-               goto out;
-       }
-
        /* one bulk endpoint writes (sources) zeroes IN (to the host) */
        ep = ss->in_ep;
        result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
@@ -966,7 +684,7 @@ fail1:
                return result;
        ep->driver_data = ss;
 
-       result = source_sink_start_ep(ss, true, EP_BULK, speed);
+       result = source_sink_start_ep(ss, true, false, speed);
        if (result < 0) {
 fail:
                ep = ss->in_ep;
@@ -985,7 +703,7 @@ fail:
                goto fail;
        ep->driver_data = ss;
 
-       result = source_sink_start_ep(ss, false, EP_BULK, speed);
+       result = source_sink_start_ep(ss, false, false, speed);
        if (result < 0) {
 fail2:
                ep = ss->out_ep;
@@ -1008,7 +726,7 @@ fail2:
                        goto fail2;
                ep->driver_data = ss;
 
-               result = source_sink_start_ep(ss, true, EP_ISOC, speed);
+               result = source_sink_start_ep(ss, true, true, speed);
                if (result < 0) {
 fail3:
                        ep = ss->iso_in_ep;
@@ -1031,14 +749,13 @@ fail3:
                        goto fail3;
                ep->driver_data = ss;
 
-               result = source_sink_start_ep(ss, false, EP_ISOC, speed);
+               result = source_sink_start_ep(ss, false, true, speed);
                if (result < 0) {
                        usb_ep_disable(ep);
                        ep->driver_data = NULL;
                        goto fail3;
                }
        }
-
 out:
        ss->cur_alt = alt;
 
@@ -1054,8 +771,6 @@ static int sourcesink_set_alt(struct usb_function *f,
 
        if (ss->in_ep->driver_data)
                disable_source_sink(ss);
-       else if (alt == 2 && ss->int_in_ep->driver_data)
-               disable_source_sink(ss);
        return enable_source_sink(cdev, ss, alt);
 }
 
@@ -1168,10 +883,6 @@ static struct usb_function *source_sink_alloc_func(
        isoc_maxpacket = ss_opts->isoc_maxpacket;
        isoc_mult = ss_opts->isoc_mult;
        isoc_maxburst = ss_opts->isoc_maxburst;
-       int_interval = ss_opts->int_interval;
-       int_maxpacket = ss_opts->int_maxpacket;
-       int_mult = ss_opts->int_mult;
-       int_maxburst = ss_opts->int_maxburst;
        buflen = ss_opts->bulk_buflen;
 
        ss->function.name = "source/sink";
@@ -1468,182 +1179,6 @@ static struct f_ss_opts_attribute f_ss_opts_bulk_buflen =
                        f_ss_opts_bulk_buflen_show,
                        f_ss_opts_bulk_buflen_store);
 
-static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_interval);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_interval_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u32 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou32(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 4096) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_interval = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_interval =
-       __CONFIGFS_ATTR(int_interval, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_interval_show,
-                       f_ss_opts_int_interval_store);
-
-static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_maxpacket);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_maxpacket_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u16 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou16(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 1024) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_maxpacket = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_maxpacket =
-       __CONFIGFS_ATTR(int_maxpacket, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_maxpacket_show,
-                       f_ss_opts_int_maxpacket_store);
-
-static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_mult);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_mult_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u8 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou8(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 2) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_mult = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_mult =
-       __CONFIGFS_ATTR(int_mult, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_mult_show,
-                       f_ss_opts_int_mult_store);
-
-static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_maxburst);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_maxburst_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u8 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou8(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 15) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_maxburst = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_maxburst =
-       __CONFIGFS_ATTR(int_maxburst, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_maxburst_show,
-                       f_ss_opts_int_maxburst_store);
-
 static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_pattern.attr,
        &f_ss_opts_isoc_interval.attr,
@@ -1651,10 +1186,6 @@ static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_isoc_mult.attr,
        &f_ss_opts_isoc_maxburst.attr,
        &f_ss_opts_bulk_buflen.attr,
-       &f_ss_opts_int_interval.attr,
-       &f_ss_opts_int_maxpacket.attr,
-       &f_ss_opts_int_mult.attr,
-       &f_ss_opts_int_maxburst.attr,
        NULL,
 };
 
@@ -1684,8 +1215,6 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
        ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
        ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
        ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;
-       ss_opts->int_interval = GZERO_INT_INTERVAL;
-       ss_opts->int_maxpacket = GZERO_INT_MAXPACKET;
 
        config_group_init_type_name(&ss_opts->func_inst.group, "",
                                    &ss_func_type);
index 33e1665..6d3eb8b 100644 (file)
@@ -54,7 +54,7 @@
 #define UNFLW_CTRL     8
 #define OVFLW_CTRL     10
 
-const char *uac2_name = "snd_uac2";
+static const char *uac2_name = "snd_uac2";
 
 struct uac2_req {
        struct uac2_rtd_params *pp; /* parent param */
@@ -634,7 +634,7 @@ static struct usb_interface_descriptor std_ac_if_desc = {
 };
 
 /* Clock source for IN traffic */
-struct uac_clock_source_descriptor in_clk_src_desc = {
+static struct uac_clock_source_descriptor in_clk_src_desc = {
        .bLength = sizeof in_clk_src_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -646,7 +646,7 @@ struct uac_clock_source_descriptor in_clk_src_desc = {
 };
 
 /* Clock source for OUT traffic */
-struct uac_clock_source_descriptor out_clk_src_desc = {
+static struct uac_clock_source_descriptor out_clk_src_desc = {
        .bLength = sizeof out_clk_src_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -658,7 +658,7 @@ struct uac_clock_source_descriptor out_clk_src_desc = {
 };
 
 /* Input Terminal for USB_OUT */
-struct uac2_input_terminal_descriptor usb_out_it_desc = {
+static struct uac2_input_terminal_descriptor usb_out_it_desc = {
        .bLength = sizeof usb_out_it_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -672,7 +672,7 @@ struct uac2_input_terminal_descriptor usb_out_it_desc = {
 };
 
 /* Input Terminal for I/O-In */
-struct uac2_input_terminal_descriptor io_in_it_desc = {
+static struct uac2_input_terminal_descriptor io_in_it_desc = {
        .bLength = sizeof io_in_it_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -686,7 +686,7 @@ struct uac2_input_terminal_descriptor io_in_it_desc = {
 };
 
 /* Ouput Terminal for USB_IN */
-struct uac2_output_terminal_descriptor usb_in_ot_desc = {
+static struct uac2_output_terminal_descriptor usb_in_ot_desc = {
        .bLength = sizeof usb_in_ot_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -700,7 +700,7 @@ struct uac2_output_terminal_descriptor usb_in_ot_desc = {
 };
 
 /* Ouput Terminal for I/O-Out */
-struct uac2_output_terminal_descriptor io_out_ot_desc = {
+static struct uac2_output_terminal_descriptor io_out_ot_desc = {
        .bLength = sizeof io_out_ot_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -713,7 +713,7 @@ struct uac2_output_terminal_descriptor io_out_ot_desc = {
        .bmControls = (CONTROL_RDWR << COPY_CTRL),
 };
 
-struct uac2_ac_header_descriptor ac_hdr_desc = {
+static struct uac2_ac_header_descriptor ac_hdr_desc = {
        .bLength = sizeof ac_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -751,7 +751,7 @@ static struct usb_interface_descriptor std_as_out_if1_desc = {
 };
 
 /* Audio Stream OUT Intface Desc */
-struct uac2_as_header_descriptor as_out_hdr_desc = {
+static struct uac2_as_header_descriptor as_out_hdr_desc = {
        .bLength = sizeof as_out_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -764,7 +764,7 @@ struct uac2_as_header_descriptor as_out_hdr_desc = {
 };
 
 /* Audio USB_OUT Format */
-struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
+static struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
        .bLength = sizeof as_out_fmt1_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype = UAC_FORMAT_TYPE,
@@ -772,7 +772,7 @@ struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
 };
 
 /* STD AS ISO OUT Endpoint */
-struct usb_endpoint_descriptor fs_epout_desc = {
+static struct usb_endpoint_descriptor fs_epout_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -782,7 +782,7 @@ struct usb_endpoint_descriptor fs_epout_desc = {
        .bInterval = 1,
 };
 
-struct usb_endpoint_descriptor hs_epout_desc = {
+static struct usb_endpoint_descriptor hs_epout_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -828,7 +828,7 @@ static struct usb_interface_descriptor std_as_in_if1_desc = {
 };
 
 /* Audio Stream IN Intface Desc */
-struct uac2_as_header_descriptor as_in_hdr_desc = {
+static struct uac2_as_header_descriptor as_in_hdr_desc = {
        .bLength = sizeof as_in_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -841,7 +841,7 @@ struct uac2_as_header_descriptor as_in_hdr_desc = {
 };
 
 /* Audio USB_IN Format */
-struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
+static struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
        .bLength = sizeof as_in_fmt1_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype = UAC_FORMAT_TYPE,
@@ -849,7 +849,7 @@ struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
 };
 
 /* STD AS ISO IN Endpoint */
-struct usb_endpoint_descriptor fs_epin_desc = {
+static struct usb_endpoint_descriptor fs_epin_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -859,7 +859,7 @@ struct usb_endpoint_descriptor fs_epin_desc = {
        .bInterval = 1,
 };
 
-struct usb_endpoint_descriptor hs_epin_desc = {
+static struct usb_endpoint_descriptor hs_epin_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -1563,7 +1563,7 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
                agdev->out_ep->driver_data = NULL;
 }
 
-struct usb_function *afunc_alloc(struct usb_function_instance *fi)
+static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
 {
        struct audio_dev *agdev;
        struct f_uac2_opts *opts;
index 2ce28b9..15f1809 100644 (file)
@@ -10,8 +10,6 @@
 #define GZERO_QLEN             32
 #define GZERO_ISOC_INTERVAL    4
 #define GZERO_ISOC_MAXPACKET   1024
-#define GZERO_INT_INTERVAL     1 /* Default interrupt interval = 1 ms */
-#define GZERO_INT_MAXPACKET    1024
 
 struct usb_zero_options {
        unsigned pattern;
@@ -19,10 +17,6 @@ struct usb_zero_options {
        unsigned isoc_maxpacket;
        unsigned isoc_mult;
        unsigned isoc_maxburst;
-       unsigned int_interval; /* In ms */
-       unsigned int_maxpacket;
-       unsigned int_mult;
-       unsigned int_maxburst;
        unsigned bulk_buflen;
        unsigned qlen;
 };
@@ -34,10 +28,6 @@ struct f_ss_opts {
        unsigned isoc_maxpacket;
        unsigned isoc_mult;
        unsigned isoc_maxburst;
-       unsigned int_interval; /* In ms */
-       unsigned int_maxpacket;
-       unsigned int_mult;
-       unsigned int_maxburst;
        unsigned bulk_buflen;
 
        /*
@@ -72,7 +62,6 @@ int lb_modinit(void);
 void free_ep_req(struct usb_ep *ep, struct usb_request *req);
 void disable_endpoints(struct usb_composite_dev *cdev,
                struct usb_ep *in, struct usb_ep *out,
-               struct usb_ep *iso_in, struct usb_ep *iso_out,
-               struct usb_ep *int_in, struct usb_ep *int_out);
+               struct usb_ep *iso_in, struct usb_ep *iso_out);
 
 #endif /* __G_ZERO_H */
index 5aad7fe..8b818fd 100644 (file)
@@ -27,6 +27,7 @@
 #include "uvc.h"
 #include "uvc_queue.h"
 #include "uvc_video.h"
+#include "uvc_v4l2.h"
 
 /* --------------------------------------------------------------------------
  * Requests handling
index 9cb86bc..50a5e63 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "uvc.h"
 #include "uvc_queue.h"
+#include "uvc_video.h"
 
 /* --------------------------------------------------------------------------
  * Video codecs
index 06acfa5..b01b88e 100644 (file)
@@ -133,7 +133,9 @@ struct gfs_configuration {
        struct usb_configuration c;
        int (*eth)(struct usb_configuration *c);
        int num;
-} gfs_configurations[] = {
+};
+
+static struct gfs_configuration gfs_configurations[] = {
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        {
                .eth            = bind_rndis_config,
@@ -278,7 +280,7 @@ static void *functionfs_acquire_dev(struct ffs_dev *dev)
        if (!try_module_get(THIS_MODULE))
                return ERR_PTR(-ENOENT);
        
-       return 0;
+       return NULL;
 }
 
 static void functionfs_release_dev(struct ffs_dev *dev)
index db49ec4..200f9a5 100644 (file)
@@ -74,6 +74,8 @@ MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");
 MODULE_LICENSE ("GPL");
 
+static int ep_open(struct inode *, struct file *);
+
 
 /*----------------------------------------------------------------------*/
 
@@ -283,14 +285,15 @@ static void epio_complete (struct usb_ep *ep, struct usb_request *req)
  * still need dev->lock to use epdata->ep.
  */
 static int
-get_ready_ep (unsigned f_flags, struct ep_data *epdata)
+get_ready_ep (unsigned f_flags, struct ep_data *epdata, bool is_write)
 {
        int     val;
 
        if (f_flags & O_NONBLOCK) {
                if (!mutex_trylock(&epdata->lock))
                        goto nonblock;
-               if (epdata->state != STATE_EP_ENABLED) {
+               if (epdata->state != STATE_EP_ENABLED &&
+                   (!is_write || epdata->state != STATE_EP_READY)) {
                        mutex_unlock(&epdata->lock);
 nonblock:
                        val = -EAGAIN;
@@ -305,18 +308,20 @@ nonblock:
 
        switch (epdata->state) {
        case STATE_EP_ENABLED:
+               return 0;
+       case STATE_EP_READY:                    /* not configured yet */
+               if (is_write)
+                       return 0;
+               // FALLTHRU
+       case STATE_EP_UNBOUND:                  /* clean disconnect */
                break;
        // case STATE_EP_DISABLED:              /* "can't happen" */
-       // case STATE_EP_READY:                 /* "can't happen" */
        default:                                /* error! */
                pr_debug ("%s: ep %p not available, state %d\n",
                                shortname, epdata, epdata->state);
-               // FALLTHROUGH
-       case STATE_EP_UNBOUND:                  /* clean disconnect */
-               val = -ENODEV;
-               mutex_unlock(&epdata->lock);
        }
-       return val;
+       mutex_unlock(&epdata->lock);
+       return -ENODEV;
 }
 
 static ssize_t
@@ -363,97 +368,6 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len)
        return value;
 }
 
-
-/* handle a synchronous OUT bulk/intr/iso transfer */
-static ssize_t
-ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       void                    *kbuf;
-       ssize_t                 value;
-
-       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
-               return value;
-
-       /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc)) {
-                       mutex_unlock(&data->lock);
-                       return -EINVAL;
-               }
-               DBG (data->dev, "%s halt\n", data->name);
-               spin_lock_irq (&data->dev->lock);
-               if (likely (data->ep != NULL))
-                       usb_ep_set_halt (data->ep);
-               spin_unlock_irq (&data->dev->lock);
-               mutex_unlock(&data->lock);
-               return -EBADMSG;
-       }
-
-       /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */
-
-       value = -ENOMEM;
-       kbuf = kmalloc (len, GFP_KERNEL);
-       if (unlikely (!kbuf))
-               goto free1;
-
-       value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
-               data->name, len, (int) value);
-       if (value >= 0 && copy_to_user (buf, kbuf, value))
-               value = -EFAULT;
-
-free1:
-       mutex_unlock(&data->lock);
-       kfree (kbuf);
-       return value;
-}
-
-/* handle a synchronous IN bulk/intr/iso transfer */
-static ssize_t
-ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       void                    *kbuf;
-       ssize_t                 value;
-
-       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
-               return value;
-
-       /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (!usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc)) {
-                       mutex_unlock(&data->lock);
-                       return -EINVAL;
-               }
-               DBG (data->dev, "%s halt\n", data->name);
-               spin_lock_irq (&data->dev->lock);
-               if (likely (data->ep != NULL))
-                       usb_ep_set_halt (data->ep);
-               spin_unlock_irq (&data->dev->lock);
-               mutex_unlock(&data->lock);
-               return -EBADMSG;
-       }
-
-       /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
-
-       value = -ENOMEM;
-       kbuf = memdup_user(buf, len);
-       if (IS_ERR(kbuf)) {
-               value = PTR_ERR(kbuf);
-               kbuf = NULL;
-               goto free1;
-       }
-
-       value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s write %zu IN, status %d\n",
-               data->name, len, (int) value);
-free1:
-       mutex_unlock(&data->lock);
-       kfree (kbuf);
-       return value;
-}
-
 static int
 ep_release (struct inode *inode, struct file *fd)
 {
@@ -481,7 +395,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
        struct ep_data          *data = fd->private_data;
        int                     status;
 
-       if ((status = get_ready_ep (fd->f_flags, data)) < 0)
+       if ((status = get_ready_ep (fd->f_flags, data, false)) < 0)
                return status;
 
        spin_lock_irq (&data->dev->lock);
@@ -517,8 +431,8 @@ struct kiocb_priv {
        struct mm_struct        *mm;
        struct work_struct      work;
        void                    *buf;
-       const struct iovec      *iv;
-       unsigned long           nr_segs;
+       struct iov_iter         to;
+       const void              *to_free;
        unsigned                actual;
 };
 
@@ -541,35 +455,6 @@ static int ep_aio_cancel(struct kiocb *iocb)
        return value;
 }
 
-static ssize_t ep_copy_to_user(struct kiocb_priv *priv)
-{
-       ssize_t                 len, total;
-       void                    *to_copy;
-       int                     i;
-
-       /* copy stuff into user buffers */
-       total = priv->actual;
-       len = 0;
-       to_copy = priv->buf;
-       for (i=0; i < priv->nr_segs; i++) {
-               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
-               if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
-                       if (len == 0)
-                               len = -EFAULT;
-                       break;
-               }
-
-               total -= this;
-               len += this;
-               to_copy += this;
-               if (total == 0)
-                       break;
-       }
-
-       return len;
-}
-
 static void ep_user_copy_worker(struct work_struct *work)
 {
        struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work);
@@ -578,13 +463,16 @@ static void ep_user_copy_worker(struct work_struct *work)
        size_t ret;
 
        use_mm(mm);
-       ret = ep_copy_to_user(priv);
+       ret = copy_to_iter(priv->buf, priv->actual, &priv->to);
        unuse_mm(mm);
+       if (!ret)
+               ret = -EFAULT;
 
        /* completing the iocb can drop the ctx and mm, don't touch mm after */
        aio_complete(iocb, ret, ret);
 
        kfree(priv->buf);
+       kfree(priv->to_free);
        kfree(priv);
 }
 
@@ -603,8 +491,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
         * don't need to copy anything to userspace, so we can
         * complete the aio request immediately.
         */
-       if (priv->iv == NULL || unlikely(req->actual == 0)) {
+       if (priv->to_free == NULL || unlikely(req->actual == 0)) {
                kfree(req->buf);
+               kfree(priv->to_free);
                kfree(priv);
                iocb->private = NULL;
                /* aio_complete() reports bytes-transferred _and_ faults */
@@ -618,6 +507,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
 
                priv->buf = req->buf;
                priv->actual = req->actual;
+               INIT_WORK(&priv->work, ep_user_copy_worker);
                schedule_work(&priv->work);
        }
        spin_unlock(&epdata->dev->lock);
@@ -626,38 +516,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
        put_ep(epdata);
 }
 
-static ssize_t
-ep_aio_rwtail(
-       struct kiocb    *iocb,
-       char            *buf,
-       size_t          len,
-       struct ep_data  *epdata,
-       const struct iovec *iv,
-       unsigned long   nr_segs
-)
+static ssize_t ep_aio(struct kiocb *iocb,
+                     struct kiocb_priv *priv,
+                     struct ep_data *epdata,
+                     char *buf,
+                     size_t len)
 {
-       struct kiocb_priv       *priv;
-       struct usb_request      *req;
-       ssize_t                 value;
+       struct usb_request *req;
+       ssize_t value;
 
-       priv = kmalloc(sizeof *priv, GFP_KERNEL);
-       if (!priv) {
-               value = -ENOMEM;
-fail:
-               kfree(buf);
-               return value;
-       }
        iocb->private = priv;
        priv->iocb = iocb;
-       priv->iv = iv;
-       priv->nr_segs = nr_segs;
-       INIT_WORK(&priv->work, ep_user_copy_worker);
-
-       value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
-       if (unlikely(value < 0)) {
-               kfree(priv);
-               goto fail;
-       }
 
        kiocb_set_cancel_fn(iocb, ep_aio_cancel);
        get_ep(epdata);
@@ -669,75 +538,154 @@ fail:
         * allocate or submit those if the host disconnected.
         */
        spin_lock_irq(&epdata->dev->lock);
-       if (likely(epdata->ep)) {
-               req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
-               if (likely(req)) {
-                       priv->req = req;
-                       req->buf = buf;
-                       req->length = len;
-                       req->complete = ep_aio_complete;
-                       req->context = iocb;
-                       value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
-                       if (unlikely(0 != value))
-                               usb_ep_free_request(epdata->ep, req);
-               } else
-                       value = -EAGAIN;
-       } else
-               value = -ENODEV;
-       spin_unlock_irq(&epdata->dev->lock);
+       value = -ENODEV;
+       if (unlikely(epdata->ep))
+               goto fail;
 
-       mutex_unlock(&epdata->lock);
+       req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
+       value = -ENOMEM;
+       if (unlikely(!req))
+               goto fail;
 
-       if (unlikely(value)) {
-               kfree(priv);
-               put_ep(epdata);
-       } else
-               value = -EIOCBQUEUED;
+       priv->req = req;
+       req->buf = buf;
+       req->length = len;
+       req->complete = ep_aio_complete;
+       req->context = iocb;
+       value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
+       if (unlikely(0 != value)) {
+               usb_ep_free_request(epdata->ep, req);
+               goto fail;
+       }
+       spin_unlock_irq(&epdata->dev->lock);
+       return -EIOCBQUEUED;
+
+fail:
+       spin_unlock_irq(&epdata->dev->lock);
+       kfree(priv->to_free);
+       kfree(priv);
+       put_ep(epdata);
        return value;
 }
 
 static ssize_t
-ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t o)
+ep_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
-       struct ep_data          *epdata = iocb->ki_filp->private_data;
-       char                    *buf;
+       struct file *file = iocb->ki_filp;
+       struct ep_data *epdata = file->private_data;
+       size_t len = iov_iter_count(to);
+       ssize_t value;
+       char *buf;
 
-       if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
-               return -EINVAL;
+       if ((value = get_ready_ep(file->f_flags, epdata, false)) < 0)
+               return value;
 
-       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
-       if (unlikely(!buf))
-               return -ENOMEM;
+       /* halt any endpoint by doing a "wrong direction" i/o call */
+       if (usb_endpoint_dir_in(&epdata->desc)) {
+               if (usb_endpoint_xfer_isoc(&epdata->desc) ||
+                   !is_sync_kiocb(iocb)) {
+                       mutex_unlock(&epdata->lock);
+                       return -EINVAL;
+               }
+               DBG (epdata->dev, "%s halt\n", epdata->name);
+               spin_lock_irq(&epdata->dev->lock);
+               if (likely(epdata->ep != NULL))
+                       usb_ep_set_halt(epdata->ep);
+               spin_unlock_irq(&epdata->dev->lock);
+               mutex_unlock(&epdata->lock);
+               return -EBADMSG;
+       }
 
-       return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs);
+       buf = kmalloc(len, GFP_KERNEL);
+       if (unlikely(!buf)) {
+               mutex_unlock(&epdata->lock);
+               return -ENOMEM;
+       }
+       if (is_sync_kiocb(iocb)) {
+               value = ep_io(epdata, buf, len);
+               if (value >= 0 && copy_to_iter(buf, value, to))
+                       value = -EFAULT;
+       } else {
+               struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL);
+               value = -ENOMEM;
+               if (!priv)
+                       goto fail;
+               priv->to_free = dup_iter(&priv->to, to, GFP_KERNEL);
+               if (!priv->to_free) {
+                       kfree(priv);
+                       goto fail;
+               }
+               value = ep_aio(iocb, priv, epdata, buf, len);
+               if (value == -EIOCBQUEUED)
+                       buf = NULL;
+       }
+fail:
+       kfree(buf);
+       mutex_unlock(&epdata->lock);
+       return value;
 }
 
+static ssize_t ep_config(struct ep_data *, const char *, size_t);
+
 static ssize_t
-ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t o)
+ep_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
-       struct ep_data          *epdata = iocb->ki_filp->private_data;
-       char                    *buf;
-       size_t                  len = 0;
-       int                     i = 0;
+       struct file *file = iocb->ki_filp;
+       struct ep_data *epdata = file->private_data;
+       size_t len = iov_iter_count(from);
+       bool configured;
+       ssize_t value;
+       char *buf;
+
+       if ((value = get_ready_ep(file->f_flags, epdata, true)) < 0)
+               return value;
 
-       if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
-               return -EINVAL;
+       configured = epdata->state == STATE_EP_ENABLED;
 
-       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
-       if (unlikely(!buf))
+       /* halt any endpoint by doing a "wrong direction" i/o call */
+       if (configured && !usb_endpoint_dir_in(&epdata->desc)) {
+               if (usb_endpoint_xfer_isoc(&epdata->desc) ||
+                   !is_sync_kiocb(iocb)) {
+                       mutex_unlock(&epdata->lock);
+                       return -EINVAL;
+               }
+               DBG (epdata->dev, "%s halt\n", epdata->name);
+               spin_lock_irq(&epdata->dev->lock);
+               if (likely(epdata->ep != NULL))
+                       usb_ep_set_halt(epdata->ep);
+               spin_unlock_irq(&epdata->dev->lock);
+               mutex_unlock(&epdata->lock);
+               return -EBADMSG;
+       }
+
+       buf = kmalloc(len, GFP_KERNEL);
+       if (unlikely(!buf)) {
+               mutex_unlock(&epdata->lock);
                return -ENOMEM;
+       }
 
-       for (i=0; i < nr_segs; i++) {
-               if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
-                               iov[i].iov_len) != 0)) {
-                       kfree(buf);
-                       return -EFAULT;
+       if (unlikely(copy_from_iter(buf, len, from) != len)) {
+               value = -EFAULT;
+               goto out;
+       }
+
+       if (unlikely(!configured)) {
+               value = ep_config(epdata, buf, len);
+       } else if (is_sync_kiocb(iocb)) {
+               value = ep_io(epdata, buf, len);
+       } else {
+               struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL);
+               value = -ENOMEM;
+               if (priv) {
+                       value = ep_aio(iocb, priv, epdata, buf, len);
+                       if (value == -EIOCBQUEUED)
+                               buf = NULL;
                }
-               len += iov[i].iov_len;
        }
-       return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
+out:
+       kfree(buf);
+       mutex_unlock(&epdata->lock);
+       return value;
 }
 
 /*----------------------------------------------------------------------*/
@@ -745,15 +693,15 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
 /* used after endpoint configuration */
 static const struct file_operations ep_io_operations = {
        .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
 
-       .read =         ep_read,
-       .write =        ep_write,
-       .unlocked_ioctl = ep_ioctl,
+       .open =         ep_open,
        .release =      ep_release,
-
-       .aio_read =     ep_aio_read,
-       .aio_write =    ep_aio_write,
+       .llseek =       no_llseek,
+       .read =         new_sync_read,
+       .write =        new_sync_write,
+       .unlocked_ioctl = ep_ioctl,
+       .read_iter =    ep_read_iter,
+       .write_iter =   ep_write_iter,
 };
 
 /* ENDPOINT INITIALIZATION
@@ -770,17 +718,12 @@ static const struct file_operations ep_io_operations = {
  * speed descriptor, then optional high speed descriptor.
  */
 static ssize_t
-ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+ep_config (struct ep_data *data, const char *buf, size_t len)
 {
-       struct ep_data          *data = fd->private_data;
        struct usb_ep           *ep;
        u32                     tag;
        int                     value, length = len;
 
-       value = mutex_lock_interruptible(&data->lock);
-       if (value < 0)
-               return value;
-
        if (data->state != STATE_EP_READY) {
                value = -EL2HLT;
                goto fail;
@@ -791,9 +734,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                goto fail0;
 
        /* we might need to change message format someday */
-       if (copy_from_user (&tag, buf, 4)) {
-               goto fail1;
-       }
+       memcpy(&tag, buf, 4);
        if (tag != 1) {
                DBG(data->dev, "config %s, bad tag %d\n", data->name, tag);
                goto fail0;
@@ -806,19 +747,15 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
         */
 
        /* full/low speed descriptor, then high speed */
-       if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) {
-               goto fail1;
-       }
+       memcpy(&data->desc, buf, USB_DT_ENDPOINT_SIZE);
        if (data->desc.bLength != USB_DT_ENDPOINT_SIZE
                        || data->desc.bDescriptorType != USB_DT_ENDPOINT)
                goto fail0;
        if (len != USB_DT_ENDPOINT_SIZE) {
                if (len != 2 * USB_DT_ENDPOINT_SIZE)
                        goto fail0;
-               if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
-                                       USB_DT_ENDPOINT_SIZE)) {
-                       goto fail1;
-               }
+               memcpy(&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
+                       USB_DT_ENDPOINT_SIZE);
                if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE
                                || data->hs_desc.bDescriptorType
                                        != USB_DT_ENDPOINT) {
@@ -840,24 +777,20 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        case USB_SPEED_LOW:
        case USB_SPEED_FULL:
                ep->desc = &data->desc;
-               value = usb_ep_enable(ep);
-               if (value == 0)
-                       data->state = STATE_EP_ENABLED;
                break;
        case USB_SPEED_HIGH:
                /* fails if caller didn't provide that descriptor... */
                ep->desc = &data->hs_desc;
-               value = usb_ep_enable(ep);
-               if (value == 0)
-                       data->state = STATE_EP_ENABLED;
                break;
        default:
                DBG(data->dev, "unconnected, %s init abandoned\n",
                                data->name);
                value = -EINVAL;
+               goto gone;
        }
+       value = usb_ep_enable(ep);
        if (value == 0) {
-               fd->f_op = &ep_io_operations;
+               data->state = STATE_EP_ENABLED;
                value = length;
        }
 gone:
@@ -867,14 +800,10 @@ fail:
                data->desc.bDescriptorType = 0;
                data->hs_desc.bDescriptorType = 0;
        }
-       mutex_unlock(&data->lock);
        return value;
 fail0:
        value = -EINVAL;
        goto fail;
-fail1:
-       value = -EFAULT;
-       goto fail;
 }
 
 static int
@@ -902,15 +831,6 @@ ep_open (struct inode *inode, struct file *fd)
        return value;
 }
 
-/* used before endpoint configuration */
-static const struct file_operations ep_config_operations = {
-       .llseek =       no_llseek,
-
-       .open =         ep_open,
-       .write =        ep_config,
-       .release =      ep_release,
-};
-
 /*----------------------------------------------------------------------*/
 
 /* EP0 IMPLEMENTATION can be partly in userspace.
@@ -989,6 +909,10 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
        enum ep0_state                  state;
 
        spin_lock_irq (&dev->lock);
+       if (dev->state <= STATE_DEV_OPENED) {
+               retval = -EINVAL;
+               goto done;
+       }
 
        /* report fd mode change before acting on it */
        if (dev->setup_abort) {
@@ -1187,8 +1111,6 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        struct dev_data         *dev = fd->private_data;
        ssize_t                 retval = -ESRCH;
 
-       spin_lock_irq (&dev->lock);
-
        /* report fd mode change before acting on it */
        if (dev->setup_abort) {
                dev->setup_abort = 0;
@@ -1234,7 +1156,6 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        } else
                DBG (dev, "fail %s, state %d\n", __func__, dev->state);
 
-       spin_unlock_irq (&dev->lock);
        return retval;
 }
 
@@ -1281,6 +1202,9 @@ ep0_poll (struct file *fd, poll_table *wait)
        struct dev_data         *dev = fd->private_data;
        int                     mask = 0;
 
+       if (dev->state <= STATE_DEV_OPENED)
+               return DEFAULT_POLLMASK;
+
        poll_wait(fd, &dev->wait, wait);
 
        spin_lock_irq (&dev->lock);
@@ -1316,19 +1240,6 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
        return ret;
 }
 
-/* used after device configuration */
-static const struct file_operations ep0_io_operations = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-
-       .read =         ep0_read,
-       .write =        ep0_write,
-       .fasync =       ep0_fasync,
-       .poll =         ep0_poll,
-       .unlocked_ioctl =       dev_ioctl,
-       .release =      dev_release,
-};
-
 /*----------------------------------------------------------------------*/
 
 /* The in-kernel gadget driver handles most ep0 issues, in particular
@@ -1650,7 +1561,7 @@ static int activate_ep_files (struct dev_data *dev)
                        goto enomem1;
 
                data->dentry = gadgetfs_create_file (dev->sb, data->name,
-                               data, &ep_config_operations);
+                               data, &ep_io_operations);
                if (!data->dentry)
                        goto enomem2;
                list_add_tail (&data->epfiles, &dev->epfiles);
@@ -1852,6 +1763,14 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        u32                     tag;
        char                    *kbuf;
 
+       spin_lock_irq(&dev->lock);
+       if (dev->state > STATE_DEV_OPENED) {
+               value = ep0_write(fd, buf, len, ptr);
+               spin_unlock_irq(&dev->lock);
+               return value;
+       }
+       spin_unlock_irq(&dev->lock);
+
        if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
                return -EINVAL;
 
@@ -1925,7 +1844,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                 * on, they can work ... except in cleanup paths that
                 * kick in after the ep0 descriptor is closed.
                 */
-               fd->f_op = &ep0_io_operations;
                value = len;
        }
        return value;
@@ -1956,12 +1874,14 @@ dev_open (struct inode *inode, struct file *fd)
        return value;
 }
 
-static const struct file_operations dev_init_operations = {
+static const struct file_operations ep0_operations = {
        .llseek =       no_llseek,
 
        .open =         dev_open,
+       .read =         ep0_read,
        .write =        dev_config,
        .fasync =       ep0_fasync,
+       .poll =         ep0_poll,
        .unlocked_ioctl = dev_ioctl,
        .release =      dev_release,
 };
@@ -2077,7 +1997,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
                goto Enomem;
 
        dev->sb = sb;
-       dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &dev_init_operations);
+       dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations);
        if (!dev->dentry) {
                put_dev(dev);
                goto Enomem;
index 3a49416..6e0a019 100644 (file)
@@ -1740,10 +1740,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
                goto err_session;
        }
        /*
-        * Now register the TCM vHost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vHost virtual I_T Nexus as active.
         */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
        mutex_unlock(&tpg->tpg_mutex);
index ff97ac9..5ee9515 100644 (file)
@@ -68,8 +68,6 @@ static struct usb_zero_options gzero_options = {
        .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
        .bulk_buflen = GZERO_BULK_BUFLEN,
        .qlen = GZERO_QLEN,
-       .int_interval = GZERO_INT_INTERVAL,
-       .int_maxpacket = GZERO_INT_MAXPACKET,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -268,21 +266,6 @@ module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
                S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
 
-module_param_named(int_interval, gzero_options.int_interval, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_interval, "1 - 16");
-
-module_param_named(int_maxpacket, gzero_options.int_maxpacket, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
-
-module_param_named(int_mult, gzero_options.int_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_mult, "0 - 2 (hs/ss only)");
-
-module_param_named(int_maxburst, gzero_options.int_maxburst, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_maxburst, "0 - 15 (ss only)");
-
 static struct usb_function *func_lb;
 static struct usb_function_instance *func_inst_lb;
 
@@ -318,10 +301,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
        ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
        ss_opts->isoc_mult = gzero_options.isoc_mult;
        ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
-       ss_opts->int_interval = gzero_options.int_interval;
-       ss_opts->int_maxpacket = gzero_options.int_maxpacket;
-       ss_opts->int_mult = gzero_options.int_mult;
-       ss_opts->int_maxburst = gzero_options.int_maxburst;
        ss_opts->bulk_buflen = gzero_options.bulk_buflen;
 
        func_ss = usb_get_function(func_inst_ss);
index 663f790..be0964a 100644 (file)
@@ -34,7 +34,6 @@ static const char hcd_name[] = "ehci-atmel";
 
 struct atmel_ehci_priv {
        struct clk *iclk;
-       struct clk *fclk;
        struct clk *uclk;
        bool clocked;
 };
@@ -51,12 +50,9 @@ static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
        if (atmel_ehci->clocked)
                return;
-       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-               clk_set_rate(atmel_ehci->uclk, 48000000);
-               clk_prepare_enable(atmel_ehci->uclk);
-       }
+
+       clk_prepare_enable(atmel_ehci->uclk);
        clk_prepare_enable(atmel_ehci->iclk);
-       clk_prepare_enable(atmel_ehci->fclk);
        atmel_ehci->clocked = true;
 }
 
@@ -64,10 +60,9 @@ static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
        if (!atmel_ehci->clocked)
                return;
-       clk_disable_unprepare(atmel_ehci->fclk);
+
        clk_disable_unprepare(atmel_ehci->iclk);
-       if (IS_ENABLED(CONFIG_COMMON_CLK))
-               clk_disable_unprepare(atmel_ehci->uclk);
+       clk_disable_unprepare(atmel_ehci->uclk);
        atmel_ehci->clocked = false;
 }
 
@@ -146,20 +141,13 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
                retval = -ENOENT;
                goto fail_request_resource;
        }
-       atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
-       if (IS_ERR(atmel_ehci->fclk)) {
-               dev_err(&pdev->dev, "Error getting function clock\n");
-               retval = -ENOENT;
+
+       atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
+       if (IS_ERR(atmel_ehci->uclk)) {
+               dev_err(&pdev->dev, "failed to get uclk\n");
+               retval = PTR_ERR(atmel_ehci->uclk);
                goto fail_request_resource;
        }
-       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-               atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
-               if (IS_ERR(atmel_ehci->uclk)) {
-                       dev_err(&pdev->dev, "failed to get uclk\n");
-                       retval = PTR_ERR(atmel_ehci->uclk);
-                       goto fail_request_resource;
-               }
-       }
 
        ehci = hcd_to_ehci(hcd);
        /* registers start at offset 0x0 */
index a7865c4..0827d7c 100644 (file)
@@ -387,6 +387,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
                status = PORT_PLC;
                port_change_bit = "link state";
                break;
+       case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
+               status = PORT_CEC;
+               port_change_bit = "config error";
+               break;
        default:
                /* Should never happen */
                return;
@@ -588,6 +592,8 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                        status |= USB_PORT_STAT_C_LINK_STATE << 16;
                if ((raw_port_status & PORT_WRC))
                        status |= USB_PORT_STAT_C_BH_RESET << 16;
+               if ((raw_port_status & PORT_CEC))
+                       status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
        }
 
        if (hcd->speed != HCD_USB3) {
@@ -1005,6 +1011,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                case USB_PORT_FEAT_C_OVER_CURRENT:
                case USB_PORT_FEAT_C_ENABLE:
                case USB_PORT_FEAT_C_PORT_LINK_STATE:
+               case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
                        xhci_clear_port_change_bit(xhci, wValue, wIndex,
                                        port_array[wIndex], temp);
                        break;
@@ -1069,7 +1076,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
         */
        status = bus_state->resuming_ports;
 
-       mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
+       mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC;
 
        spin_lock_irqsave(&xhci->lock, flags);
        /* For each port, did anything change?  If so, set that bit in buf. */
index 7f76c8a..2af32e2 100644 (file)
@@ -37,6 +37,9 @@
 
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI     0x8c31
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI  0x9c31
+#define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI            0x22b5
+#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI                0xa12f
+#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI       0x9d2f
 
 static const char hcd_name[] = "xhci_hcd";
 
@@ -112,6 +115,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
                xhci->quirks |= XHCI_LPM_SUPPORT;
                xhci->quirks |= XHCI_INTEL_HOST;
+               xhci->quirks |= XHCI_AVOID_BEI;
        }
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
                        pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
@@ -127,12 +131,17 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                 * PPT chipsets.
                 */
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
-               xhci->quirks |= XHCI_AVOID_BEI;
        }
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
                pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
        }
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+               (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
+                pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
+                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) {
+               xhci->quirks |= XHCI_PME_STUCK_QUIRK;
+       }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_EJ168) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -159,6 +168,21 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                                "QUIRK: Resetting on resume");
 }
 
+/*
+ * Make sure PME works on some Intel xHCI controllers by writing 1 to clear
+ * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
+ */
+static void xhci_pme_quirk(struct xhci_hcd *xhci)
+{
+       u32 val;
+       void __iomem *reg;
+
+       reg = (void __iomem *) xhci->cap_regs + 0x80a4;
+       val = readl(reg);
+       writel(val | BIT(28), reg);
+       readl(reg);
+}
+
 /* called during probe() after chip reset completes */
 static int xhci_pci_setup(struct usb_hcd *hcd)
 {
@@ -283,6 +307,9 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
        if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
                pdev->no_d3cold = true;
 
+       if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
+               xhci_pme_quirk(xhci);
+
        return xhci_suspend(xhci, do_wakeup);
 }
 
@@ -313,6 +340,9 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
        if (pdev->vendor == PCI_VENDOR_ID_INTEL)
                usb_enable_intel_xhci_ports(pdev);
 
+       if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
+               xhci_pme_quirk(xhci);
+
        retval = xhci_resume(xhci, hibernated);
        return retval;
 }
index 08d402b..0e11d61 100644 (file)
@@ -83,16 +83,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
        if (irq < 0)
                return -ENODEV;
 
-
-       if (of_device_is_compatible(pdev->dev.of_node,
-                                   "marvell,armada-375-xhci") ||
-           of_device_is_compatible(pdev->dev.of_node,
-                                   "marvell,armada-380-xhci")) {
-               ret = xhci_mvebu_mbus_init_quirk(pdev);
-               if (ret)
-                       return ret;
-       }
-
        /* Initialize dma_mask and coherent_dma_mask to 32-bits */
        ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
        if (ret)
@@ -127,6 +117,15 @@ static int xhci_plat_probe(struct platform_device *pdev)
                        goto put_hcd;
        }
 
+       if (of_device_is_compatible(pdev->dev.of_node,
+                                   "marvell,armada-375-xhci") ||
+           of_device_is_compatible(pdev->dev.of_node,
+                                   "marvell,armada-380-xhci")) {
+               ret = xhci_mvebu_mbus_init_quirk(pdev);
+               if (ret)
+                       goto disable_clk;
+       }
+
        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret)
                goto disable_clk;
index 88da8d6..73485fa 100644 (file)
@@ -1946,7 +1946,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
        if (event_trb != ep_ring->dequeue) {
                /* The event was for the status stage */
                if (event_trb == td->last_trb) {
-                       if (td->urb->actual_length != 0) {
+                       if (td->urb_length_set) {
                                /* Don't overwrite a previously set error code
                                 */
                                if ((*status == -EINPROGRESS || *status == 0) &&
@@ -1960,7 +1960,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                                        td->urb->transfer_buffer_length;
                        }
                } else {
-               /* Maybe the event was for the data stage? */
+                       /*
+                        * Maybe the event was for the data stage? If so, update
+                        * already the actual_length of the URB and flag it as
+                        * set, so that it is not overwritten in the event for
+                        * the last TRB.
+                        */
+                       td->urb_length_set = true;
                        td->urb->actual_length =
                                td->urb->transfer_buffer_length -
                                EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
index 9745147..8e421b8 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * xHCI host controller driver
  *
@@ -88,9 +89,10 @@ struct xhci_cap_regs {
 #define HCS_IST(p)             (((p) >> 0) & 0xf)
 /* bits 4:7, max number of Event Ring segments */
 #define HCS_ERST_MAX(p)                (((p) >> 4) & 0xf)
+/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */
 /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
-/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */
-#define HCS_MAX_SCRATCHPAD(p)   (((p) >> 27) & 0x1f)
+/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */
+#define HCS_MAX_SCRATCHPAD(p)   ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f))
 
 /* HCSPARAMS3 - hcs_params3 - bitmasks */
 /* bits 0:7, Max U1 to U0 latency for the roothub ports */
@@ -1288,6 +1290,8 @@ struct xhci_td {
        struct xhci_segment     *start_seg;
        union xhci_trb          *first_trb;
        union xhci_trb          *last_trb;
+       /* actual_length of the URB has already been set */
+       bool                    urb_length_set;
 };
 
 /* xHCI command default timeout value */
@@ -1560,6 +1564,7 @@ struct xhci_hcd {
 #define XHCI_SPURIOUS_WAKEUP   (1 << 18)
 /* For controllers with a broken beyond repair streams implementation */
 #define XHCI_BROKEN_STREAMS    (1 << 19)
+#define XHCI_PME_STUCK_QUIRK   (1 << 20)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
index b982755..bfa402c 100644 (file)
@@ -151,8 +151,7 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
        }
 
        if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
-               ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
-                                          IRQF_DISABLED);
+               ret = isp1760_udc_register(isp, irq, irqflags);
                if (ret < 0) {
                        isp1760_hcd_unregister(&isp->hcd);
                        return ret;
index eba9b82..3cb98b1 100644 (file)
@@ -1274,7 +1274,7 @@ static void errata2_function(unsigned long data)
        for (slot = 0; slot < 32; slot++)
                if (priv->atl_slots[slot].qh && time_after(jiffies,
                                        priv->atl_slots[slot].timestamp +
-                                       SLOT_TIMEOUT * HZ / 1000)) {
+                                       msecs_to_jiffies(SLOT_TIMEOUT))) {
                        ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
                        if (!FROM_DW0_VALID(ptd.dw0) &&
                                        !FROM_DW3_ACTIVE(ptd.dw3))
@@ -1286,7 +1286,7 @@ static void errata2_function(unsigned long data)
 
        spin_unlock_irqrestore(&priv->lock, spinflags);
 
-       errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+       errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
        add_timer(&errata2_timer);
 }
 
@@ -1336,7 +1336,7 @@ static int isp1760_run(struct usb_hcd *hcd)
                return retval;
 
        setup_timer(&errata2_timer, errata2_function, (unsigned long)hcd);
-       errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+       errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
        add_timer(&errata2_timer);
 
        chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
index 9612d79..3fc4fe7 100644 (file)
@@ -1191,6 +1191,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
                             struct usb_gadget_driver *driver)
 {
        struct isp1760_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
 
        /* The hardware doesn't support low speed. */
        if (driver->max_speed < USB_SPEED_FULL) {
@@ -1198,17 +1199,17 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
                return -EINVAL;
        }
 
-       spin_lock(&udc->lock);
+       spin_lock_irqsave(&udc->lock, flags);
 
        if (udc->driver) {
                dev_err(udc->isp->dev, "UDC already has a gadget driver\n");
-               spin_unlock(&udc->lock);
+               spin_unlock_irqrestore(&udc->lock, flags);
                return -EBUSY;
        }
 
        udc->driver = driver;
 
-       spin_unlock(&udc->lock);
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        dev_dbg(udc->isp->dev, "starting UDC with driver %s\n",
                driver->function);
@@ -1232,6 +1233,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
 static int isp1760_udc_stop(struct usb_gadget *gadget)
 {
        struct isp1760_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
 
        dev_dbg(udc->isp->dev, "%s\n", __func__);
 
@@ -1239,9 +1241,9 @@ static int isp1760_udc_stop(struct usb_gadget *gadget)
 
        isp1760_udc_write(udc, DC_MODE, 0);
 
-       spin_lock(&udc->lock);
+       spin_lock_irqsave(&udc->lock, flags);
        udc->driver = NULL;
-       spin_unlock(&udc->lock);
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        return 0;
 }
@@ -1411,7 +1413,7 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
                return -ENODEV;
        }
 
-       if (chipid != 0x00011582) {
+       if (chipid != 0x00011582 && chipid != 0x00158210) {
                dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid);
                return -ENODEV;
        }
@@ -1451,8 +1453,8 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq,
 
        sprintf(udc->irqname, "%s (udc)", devname);
 
-       ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | IRQF_DISABLED |
-                         irqflags, udc->irqname, udc);
+       ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags,
+                         udc->irqname, udc);
        if (ret < 0)
                goto error;
 
index 14e1628..39db8b6 100644 (file)
@@ -79,7 +79,8 @@ config USB_MUSB_TUSB6010
 
 config USB_MUSB_OMAP2PLUS
        tristate "OMAP2430 and onwards"
-       depends on ARCH_OMAP2PLUS && USB && OMAP_CONTROL_PHY
+       depends on ARCH_OMAP2PLUS && USB
+       depends on OMAP_CONTROL_PHY || !OMAP_CONTROL_PHY
        select GENERIC_PHY
 
 config USB_MUSB_AM35X
index e6f4cbf..067920f 100644 (file)
@@ -1969,10 +1969,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                goto fail0;
        }
 
-       pm_runtime_use_autosuspend(musb->controller);
-       pm_runtime_set_autosuspend_delay(musb->controller, 200);
-       pm_runtime_enable(musb->controller);
-
        spin_lock_init(&musb->lock);
        musb->board_set_power = plat->set_power;
        musb->min_power = plat->min_power;
@@ -1991,6 +1987,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        musb_readl = musb_default_readl;
        musb_writel = musb_default_writel;
 
+       /* We need musb_read/write functions initialized for PM */
+       pm_runtime_use_autosuspend(musb->controller);
+       pm_runtime_set_autosuspend_delay(musb->controller, 200);
+       pm_runtime_irq_safe(musb->controller);
+       pm_runtime_enable(musb->controller);
+
        /* The musb_platform_init() call:
         *   - adjusts musb->mregs
         *   - sets the musb->isr
index 53bd0e7..a900c98 100644 (file)
@@ -457,12 +457,27 @@ static int dsps_musb_init(struct musb *musb)
        if (IS_ERR(musb->xceiv))
                return PTR_ERR(musb->xceiv);
 
+       musb->phy = devm_phy_get(dev->parent, "usb2-phy");
+
        /* Returns zero if e.g. not clocked */
        rev = dsps_readl(reg_base, wrp->revision);
        if (!rev)
                return -ENODEV;
 
        usb_phy_init(musb->xceiv);
+       if (IS_ERR(musb->phy))  {
+               musb->phy = NULL;
+       } else {
+               ret = phy_init(musb->phy);
+               if (ret < 0)
+                       return ret;
+               ret = phy_power_on(musb->phy);
+               if (ret) {
+                       phy_exit(musb->phy);
+                       return ret;
+               }
+       }
+
        setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
 
        /* Reset the musb */
@@ -502,6 +517,8 @@ static int dsps_musb_exit(struct musb *musb)
 
        del_timer_sync(&glue->timer);
        usb_phy_shutdown(musb->xceiv);
+       phy_power_off(musb->phy);
+       phy_exit(musb->phy);
        debugfs_remove_recursive(glue->dbgfs_root);
 
        return 0;
@@ -610,7 +627,7 @@ static int dsps_musb_reset(struct musb *musb)
        struct device *dev = musb->controller;
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
-       int session_restart = 0;
+       int session_restart = 0, error;
 
        if (glue->sw_babble_enabled)
                session_restart = sw_babble_control(musb);
@@ -624,8 +641,14 @@ static int dsps_musb_reset(struct musb *musb)
                dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset));
                usleep_range(100, 200);
                usb_phy_shutdown(musb->xceiv);
+               error = phy_power_off(musb->phy);
+               if (error)
+                       dev_err(dev, "phy shutdown failed: %i\n", error);
                usleep_range(100, 200);
                usb_phy_init(musb->xceiv);
+               error = phy_power_on(musb->phy);
+               if (error)
+                       dev_err(dev, "phy powerup failed: %i\n", error);
                session_restart = 1;
        }
 
@@ -687,7 +710,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
        struct musb_hdrc_config *config;
        struct platform_device *musb;
        struct device_node *dn = parent->dev.of_node;
-       int ret;
+       int ret, val;
 
        memset(resources, 0, sizeof(resources));
        res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc");
@@ -739,7 +762,10 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
        pdata.mode = get_musb_port_mode(dev);
        /* DT keeps this entry in mA, musb expects it as per USB spec */
        pdata.power = get_int_prop(dn, "mentor,power") / 2;
-       config->multipoint = of_property_read_bool(dn, "mentor,multipoint");
+
+       ret = of_property_read_u32(dn, "mentor,multipoint", &val);
+       if (!ret && val)
+               config->multipoint = true;
 
        ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
        if (ret) {
index 883a9ad..c3d5fc9 100644 (file)
@@ -2613,7 +2613,7 @@ static const struct hc_driver musb_hc_driver = {
        .description            = "musb-hcd",
        .product_desc           = "MUSB HDRC host driver",
        .hcd_priv_size          = sizeof(struct musb *),
-       .flags                  = HCD_USB2 | HCD_MEMORY,
+       .flags                  = HCD_USB2 | HCD_MEMORY | HCD_BH,
 
        /* not using irq handler or reset hooks from usbcore, since
         * those must be shared with peripheral code for OTG configs
index 763649e..cc752d8 100644 (file)
@@ -516,7 +516,7 @@ static int omap2430_probe(struct platform_device *pdev)
        struct omap2430_glue            *glue;
        struct device_node              *np = pdev->dev.of_node;
        struct musb_hdrc_config         *config;
-       int                             ret = -ENOMEM;
+       int                             ret = -ENOMEM, val;
 
        glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
        if (!glue)
@@ -559,7 +559,10 @@ static int omap2430_probe(struct platform_device *pdev)
                of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
                of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
                of_property_read_u32(np, "power", (u32 *)&pdata->power);
-               config->multipoint = of_property_read_bool(np, "multipoint");
+
+               ret = of_property_read_u32(np, "multipoint", &val);
+               if (!ret && val)
+                       config->multipoint = true;
 
                pdata->board_data       = data;
                pdata->config           = config;
index 403fab7..7b3035f 100644 (file)
@@ -126,6 +126,9 @@ struct phy_control *am335x_get_phy_control(struct device *dev)
                return NULL;
 
        dev = bus_find_device(&platform_bus_type, NULL, node, match);
+       if (!dev)
+               return NULL;
+
        ctrl_usb = dev_get_drvdata(dev);
        if (!ctrl_usb)
                return NULL;
index de83b9d..ebc99ee 100644 (file)
@@ -6,6 +6,7 @@ config USB_RENESAS_USBHS
        tristate 'Renesas USBHS controller'
        depends on USB_GADGET
        depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+       depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in
        default n
        help
          Renesas USBHS is a discrete USB host and peripheral controller chip
index 9374bd2..8936a83 100644 (file)
@@ -38,56 +38,51 @@ static int usb_serial_device_match(struct device *dev,
        return 0;
 }
 
-static ssize_t port_number_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct usb_serial_port *port = to_usb_serial_port(dev);
-
-       return sprintf(buf, "%d\n", port->port_number);
-}
-static DEVICE_ATTR_RO(port_number);
-
 static int usb_serial_device_probe(struct device *dev)
 {
        struct usb_serial_driver *driver;
        struct usb_serial_port *port;
+       struct device *tty_dev;
        int retval = 0;
        int minor;
 
        port = to_usb_serial_port(dev);
-       if (!port) {
-               retval = -ENODEV;
-               goto exit;
-       }
+       if (!port)
+               return -ENODEV;
 
        /* make sure suspend/resume doesn't race against port_probe */
        retval = usb_autopm_get_interface(port->serial->interface);
        if (retval)
-               goto exit;
+               return retval;
 
        driver = port->serial->type;
        if (driver->port_probe) {
                retval = driver->port_probe(port);
                if (retval)
-                       goto exit_with_autopm;
+                       goto err_autopm_put;
        }
 
-       retval = device_create_file(dev, &dev_attr_port_number);
-       if (retval) {
-               if (driver->port_remove)
-                       retval = driver->port_remove(port);
-               goto exit_with_autopm;
+       minor = port->minor;
+       tty_dev = tty_register_device(usb_serial_tty_driver, minor, dev);
+       if (IS_ERR(tty_dev)) {
+               retval = PTR_ERR(tty_dev);
+               goto err_port_remove;
        }
 
-       minor = port->minor;
-       tty_register_device(usb_serial_tty_driver, minor, dev);
+       usb_autopm_put_interface(port->serial->interface);
+
        dev_info(&port->serial->dev->dev,
                 "%s converter now attached to ttyUSB%d\n",
                 driver->description, minor);
 
-exit_with_autopm:
+       return 0;
+
+err_port_remove:
+       if (driver->port_remove)
+               driver->port_remove(port);
+err_autopm_put:
        usb_autopm_put_interface(port->serial->interface);
-exit:
+
        return retval;
 }
 
@@ -114,8 +109,6 @@ static int usb_serial_device_remove(struct device *dev)
        minor = port->minor;
        tty_unregister_device(usb_serial_tty_driver, minor);
 
-       device_remove_file(&port->dev, &dev_attr_port_number);
-
        driver = port->serial->type;
        if (driver->port_remove)
                retval = driver->port_remove(port);
index 2d72aa3..ede4f5f 100644 (file)
@@ -84,6 +84,10 @@ struct ch341_private {
        u8 line_status; /* active status of modem control inputs */
 };
 
+static void ch341_set_termios(struct tty_struct *tty,
+                             struct usb_serial_port *port,
+                             struct ktermios *old_termios);
+
 static int ch341_control_out(struct usb_device *dev, u8 request,
                             u16 value, u16 index)
 {
@@ -309,19 +313,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct ch341_private *priv = usb_get_serial_port_data(port);
        int r;
 
-       priv->baud_rate = DEFAULT_BAUD_RATE;
-
        r = ch341_configure(serial->dev, priv);
        if (r)
                goto out;
 
-       r = ch341_set_handshake(serial->dev, priv->line_control);
-       if (r)
-               goto out;
-
-       r = ch341_set_baudrate(serial->dev, priv);
-       if (r)
-               goto out;
+       if (tty)
+               ch341_set_termios(tty, port, NULL);
 
        dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__);
        r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
index 29fa1c3..3806e70 100644 (file)
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/tty.h>
 #include <linux/console.h>
@@ -144,6 +145,7 @@ static int usb_console_setup(struct console *co, char *options)
                        init_ldsem(&tty->ldisc_sem);
                        INIT_LIST_HEAD(&tty->tty_files);
                        kref_get(&tty->driver->kref);
+                       __module_get(tty->driver->owner);
                        tty->ops = &usb_console_fake_tty_ops;
                        if (tty_init_termios(tty)) {
                                retval = -ENOMEM;
index f40c856..84ce2d7 100644 (file)
@@ -147,6 +147,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
        { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
        { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
+       { USB_DEVICE(0x16C0, 0x09B0) }, /* Lunatico Seletek */
+       { USB_DEVICE(0x16C0, 0x09B1) }, /* Lunatico Seletek */
        { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
        { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
        { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
index 1ebb351..8eb68a3 100644 (file)
@@ -604,6 +604,7 @@ static const struct usb_device_id id_table_combined[] = {
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) },
        /*
         * ELV devices:
         */
@@ -799,6 +800,8 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
+       { USB_DEVICE(FTDI_VID, CYBER_CORTEX_AV_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID),
@@ -978,6 +981,23 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) },
        /* GE Healthcare devices */
        { USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) },
+       /* Active Research (Actisense) devices */
+       { USB_DEVICE(FTDI_VID, ACTISENSE_NDC_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_USG_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_NGT_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_NGW_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_D9AC_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_D9AD_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_D9AE_PID) },
+       { USB_DEVICE(FTDI_VID, ACTISENSE_D9AF_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEAGAUGE_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASWITCH_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_NMEA2000_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ETHERNET_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_WIFI_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
+       { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
        { }                                     /* Terminating entry */
 };
 
@@ -1864,8 +1884,12 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
 {
        struct usb_device *udev = serial->dev;
 
-       if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
-           (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2")))
+       if (udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems"))
+               return ftdi_jtag_probe(serial);
+
+       if (udev->product &&
+               (!strcmp(udev->product, "BeagleBone/XDS100V2") ||
+                !strcmp(udev->product, "SNAP Connect E10")))
                return ftdi_jtag_probe(serial);
 
        return 0;
index e52409c..4e4f46f 100644 (file)
@@ -38,6 +38,9 @@
 
 #define FTDI_LUMEL_PD12_PID    0x6002
 
+/* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
+#define CYBER_CORTEX_AV_PID    0x8698
+
 /*
  * Marvell OpenRD Base, Client
  * http://www.open-rd.org
  */
 #define FTDI_NT_ORIONLXM_PID   0x7c90  /* OrionLXm Substation Automation Platform */
 
+/*
+ * Synapse Wireless product ids (FTDI_VID)
+ * http://www.synapse-wireless.com
+ */
+#define FTDI_SYNAPSE_SS200_PID 0x9090 /* SS200 - SNAP Stick 200 */
+
 
 /********************************/
 /** third-party VID/PID combos **/
  */
 #define GE_HEALTHCARE_VID              0x1901
 #define GE_HEALTHCARE_NEMO_TRACKER_PID 0x0015
+
+/*
+ * Active Research (Actisense) devices
+ */
+#define ACTISENSE_NDC_PID              0xD9A8 /* NDC USB Serial Adapter */
+#define ACTISENSE_USG_PID              0xD9A9 /* USG USB Serial Adapter */
+#define ACTISENSE_NGT_PID              0xD9AA /* NGT NMEA2000 Interface */
+#define ACTISENSE_NGW_PID              0xD9AB /* NGW NMEA2000 Gateway */
+#define ACTISENSE_D9AC_PID             0xD9AC /* Actisense Reserved */
+#define ACTISENSE_D9AD_PID             0xD9AD /* Actisense Reserved */
+#define ACTISENSE_D9AE_PID             0xD9AE /* Actisense Reserved */
+#define ACTISENSE_D9AF_PID             0xD9AF /* Actisense Reserved */
+#define CHETCO_SEAGAUGE_PID            0xA548 /* SeaGauge USB Adapter */
+#define CHETCO_SEASWITCH_PID           0xA549 /* SeaSwitch USB Adapter */
+#define CHETCO_SEASMART_NMEA2000_PID   0xA54A /* SeaSmart NMEA2000 Gateway */
+#define CHETCO_SEASMART_ETHERNET_PID   0xA54B /* SeaSmart Ethernet Gateway */
+#define CHETCO_SEASMART_WIFI_PID       0xA5AC /* SeaSmart Wifi Gateway */
+#define CHETCO_SEASMART_DISPLAY_PID    0xA5AD /* SeaSmart NMEA2000 Display */
+#define CHETCO_SEASMART_LITE_PID       0xA5AE /* SeaSmart Lite USB Adapter */
+#define CHETCO_SEASMART_ANALOG_PID     0xA5AF /* SeaSmart Analog Adapter */
index ccf1df7..54e170d 100644 (file)
@@ -258,7 +258,8 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
         * character or at least one jiffy.
         */
        period = max_t(unsigned long, (10 * HZ / bps), 1);
-       period = min_t(unsigned long, period, timeout);
+       if (timeout)
+               period = min_t(unsigned long, period, timeout);
 
        dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n",
                                        __func__, jiffies_to_msecs(timeout),
@@ -268,7 +269,7 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
                schedule_timeout_interruptible(period);
                if (signal_pending(current))
                        break;
-               if (time_after(jiffies, expire))
+               if (timeout && time_after(jiffies, expire))
                        break;
        }
 }
index dd97d8b..4f7e072 100644 (file)
@@ -61,6 +61,7 @@ struct keyspan_pda_private {
 /* For Xircom PGSDB9 and older Entrega version of the same device */
 #define XIRCOM_VENDOR_ID               0x085a
 #define XIRCOM_FAKE_ID                 0x8027
+#define XIRCOM_FAKE_ID_2               0x8025 /* "PGMFHUB" serial */
 #define ENTREGA_VENDOR_ID              0x1645
 #define ENTREGA_FAKE_ID                        0x8093
 
@@ -70,6 +71,7 @@ static const struct usb_device_id id_table_combined[] = {
 #endif
 #ifdef XIRCOM
        { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
+       { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
        { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
 #endif
        { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
@@ -93,6 +95,7 @@ static const struct usb_device_id id_table_fake[] = {
 #ifdef XIRCOM
 static const struct usb_device_id id_table_fake_xircom[] = {
        { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
+       { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
        { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
        { }
 };
index ab1d690..460a406 100644 (file)
@@ -1284,7 +1284,8 @@ static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port)
        }
 
        /* Initial port termios */
-       mxuport_set_termios(tty, port, NULL);
+       if (tty)
+               mxuport_set_termios(tty, port, NULL);
 
        /*
         * TODO: use RQ_VENDOR_GET_MSR, once we know what it
index 0f872e6..829604d 100644 (file)
@@ -132,6 +132,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define UART_OVERRUN_ERROR             0x40
 #define UART_CTS                       0x80
 
+static void pl2303_set_break(struct usb_serial_port *port, bool enable);
 
 enum pl2303_type {
        TYPE_01,        /* Type 0 and 1 (difference unknown) */
@@ -615,6 +616,7 @@ static void pl2303_close(struct usb_serial_port *port)
 {
        usb_serial_generic_close(port);
        usb_kill_urb(port->interrupt_in_urb);
+       pl2303_set_break(port, false);
 }
 
 static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -741,17 +743,16 @@ static int pl2303_ioctl(struct tty_struct *tty,
        return -ENOIOCTLCMD;
 }
 
-static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
+static void pl2303_set_break(struct usb_serial_port *port, bool enable)
 {
-       struct usb_serial_port *port = tty->driver_data;
        struct usb_serial *serial = port->serial;
        u16 state;
        int result;
 
-       if (break_state == 0)
-               state = BREAK_OFF;
-       else
+       if (enable)
                state = BREAK_ON;
+       else
+               state = BREAK_OFF;
 
        dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
                        state == BREAK_OFF ? "off" : "on");
@@ -763,6 +764,13 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
                dev_err(&port->dev, "error sending break = %d\n", result);
 }
 
+static void pl2303_break_ctl(struct tty_struct *tty, int state)
+{
+       struct usb_serial_port *port = tty->driver_data;
+
+       pl2303_set_break(port, state);
+}
+
 static void pl2303_update_line_status(struct usb_serial_port *port,
                                      unsigned char *data,
                                      unsigned int actual_length)
index 475723c..529066b 100644 (file)
@@ -687,6 +687,21 @@ static void serial_port_dtr_rts(struct tty_port *port, int on)
                drv->dtr_rts(p, on);
 }
 
+static ssize_t port_number_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+
+       return sprintf(buf, "%u\n", port->port_number);
+}
+static DEVICE_ATTR_RO(port_number);
+
+static struct attribute *usb_serial_port_attrs[] = {
+       &dev_attr_port_number.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(usb_serial_port);
+
 static const struct tty_port_operations serial_port_ops = {
        .carrier_raised         = serial_port_carrier_raised,
        .dtr_rts                = serial_port_dtr_rts,
@@ -902,6 +917,7 @@ static int usb_serial_probe(struct usb_interface *interface,
                port->dev.driver = NULL;
                port->dev.bus = &usb_serial_bus_type;
                port->dev.release = &usb_serial_port_release;
+               port->dev.groups = usb_serial_port_groups;
                device_initialize(&port->dev);
        }
 
@@ -940,8 +956,9 @@ static int usb_serial_probe(struct usb_interface *interface,
                port = serial->port[i];
                if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
                        goto probe_error;
-               buffer_size = max_t(int, serial->type->bulk_out_size,
-                                               usb_endpoint_maxp(endpoint));
+               buffer_size = serial->type->bulk_out_size;
+               if (!buffer_size)
+                       buffer_size = usb_endpoint_maxp(endpoint);
                port->bulk_out_size = buffer_size;
                port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
 
index dbc00e5..c85ea53 100644 (file)
@@ -113,6 +113,20 @@ UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
 
+/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
+UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
+               "Initio Corporation",
+               "",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_ATA_1X),
+
+/* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
+UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
+               "JMicron",
+               "JMS539",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_REPORT_OPCODES),
+
 /* Reported-by: Claudio Bizzarri <claudio.bizzarri@gmail.com> */
 UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
                "JMicron",
index d468d02..5600c33 100644 (file)
@@ -889,6 +889,12 @@ static void usb_stor_scan_dwork(struct work_struct *work)
            !(us->fflags & US_FL_SCM_MULT_TARG)) {
                mutex_lock(&us->dev_mutex);
                us->max_lun = usb_stor_Bulk_max_lun(us);
+               /*
+                * Allow proper scanning of devices that present more than 8 LUNs
+                * While not affecting other devices that may need the previous behavior
+                */
+               if (us->max_lun >= 8)
+                       us_to_host(us)->max_lun = us->max_lun+1;
                mutex_unlock(&us->dev_mutex);
        }
        scsi_scan_host(us_to_host(us));
index f88bfdf..2027a27 100644 (file)
@@ -868,12 +868,14 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
                                func = vfio_pci_set_err_trigger;
                        break;
                }
+               break;
        case VFIO_PCI_REQ_IRQ_INDEX:
                switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
                case VFIO_IRQ_SET_ACTION_TRIGGER:
                        func = vfio_pci_set_req_trigger;
                        break;
                }
+               break;
        }
 
        if (!func)
index afa06d2..2bbfc25 100644 (file)
@@ -591,11 +591,6 @@ static void handle_rx(struct vhost_net *net)
                         * TODO: support TSO.
                         */
                        iov_iter_advance(&msg.msg_iter, vhost_hlen);
-               } else {
-                       /* It'll come from socket; we'll need to patch
-                        * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
-                        */
-                       iov_iter_advance(&fixup, sizeof(hdr));
                }
                err = sock->ops->recvmsg(NULL, sock, &msg,
                                         sock_len, MSG_DONTWAIT | MSG_TRUNC);
@@ -609,17 +604,25 @@ static void handle_rx(struct vhost_net *net)
                        continue;
                }
                /* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */
-               if (unlikely(vhost_hlen) &&
-                   copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) {
-                       vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
-                              vq->iov->iov_base);
-                       break;
+               if (unlikely(vhost_hlen)) {
+                       if (copy_to_iter(&hdr, sizeof(hdr),
+                                        &fixup) != sizeof(hdr)) {
+                               vq_err(vq, "Unable to write vnet_hdr "
+                                      "at addr %p\n", vq->iov->iov_base);
+                               break;
+                       }
+               } else {
+                       /* Header came from socket; we'll need to patch
+                        * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
+                        */
+                       iov_iter_advance(&fixup, sizeof(hdr));
                }
                /* TODO: Should check and handle checksum. */
 
                num_buffers = cpu_to_vhost16(vq, headcount);
                if (likely(mergeable) &&
-                   copy_to_iter(&num_buffers, 2, &fixup) != 2) {
+                   copy_to_iter(&num_buffers, sizeof num_buffers,
+                                &fixup) != sizeof num_buffers) {
                        vq_err(vq, "Failed num_buffers write");
                        vhost_discard_vq_desc(vq, headcount);
                        break;
index 8d4f3f1..71df240 100644 (file)
@@ -1956,10 +1956,9 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
                goto out;
        }
        /*
-        * Now register the TCM vhost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vhost virtual I_T Nexus as active.
         */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index 32c0b6b..9362424 100644 (file)
@@ -599,6 +599,9 @@ static int clcdfb_of_get_mode(struct device *dev, struct device_node *endpoint,
 
        len = clcdfb_snprintf_mode(NULL, 0, mode);
        name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
        clcdfb_snprintf_mode(name, len + 1, mode);
        mode->name = name;
 
index 9533859..868facd 100644 (file)
@@ -624,9 +624,6 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
        int num = 0, i, first = 1;
        int ver, rev;
 
-       ver = edid[EDID_STRUCT_VERSION];
-       rev = edid[EDID_STRUCT_REVISION];
-
        mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
        if (mode == NULL)
                return NULL;
@@ -637,6 +634,9 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
                return NULL;
        }
 
+       ver = edid[EDID_STRUCT_VERSION];
+       rev = edid[EDID_STRUCT_REVISION];
+
        *dbsize = 0;
 
        DPRINTK("   Detailed Timings\n");
index 5a2095a..1218655 100644 (file)
 #include <video/omapdss.h>
 #include "dss.h"
 
-static struct omap_dss_device *to_dss_device_sysfs(struct device *dev)
+static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = NULL;
-
-       for_each_dss_dev(dssdev) {
-               if (dssdev->dev == dev) {
-                       omap_dss_put_device(dssdev);
-                       return dssdev;
-               }
-       }
-
-       return NULL;
-}
-
-static ssize_t display_name_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
-
        return snprintf(buf, PAGE_SIZE, "%s\n",
                        dssdev->name ?
                        dssdev->name : "");
 }
 
-static ssize_t display_enabled_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
-
        return snprintf(buf, PAGE_SIZE, "%d\n",
                        omapdss_device_is_enabled(dssdev));
 }
 
-static ssize_t display_enabled_store(struct device *dev,
-               struct device_attribute *attr,
+static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
                const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool enable;
 
@@ -90,19 +68,16 @@ static ssize_t display_enabled_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_tear_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        return snprintf(buf, PAGE_SIZE, "%d\n",
                        dssdev->driver->get_te ?
                        dssdev->driver->get_te(dssdev) : 0);
 }
 
-static ssize_t display_tear_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_tear_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool te;
 
@@ -120,10 +95,8 @@ static ssize_t display_tear_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_timings_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        struct omap_video_timings t;
 
        if (!dssdev->driver->get_timings)
@@ -137,10 +110,9 @@ static ssize_t display_timings_show(struct device *dev,
                        t.y_res, t.vfp, t.vbp, t.vsw);
 }
 
-static ssize_t display_timings_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_timings_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        struct omap_video_timings t = dssdev->panel.timings;
        int r, found;
 
@@ -176,10 +148,8 @@ static ssize_t display_timings_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_rotate_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int rotate;
        if (!dssdev->driver->get_rotate)
                return -ENOENT;
@@ -187,10 +157,9 @@ static ssize_t display_rotate_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
 }
 
-static ssize_t display_rotate_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int rot, r;
 
        if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
@@ -207,10 +176,8 @@ static ssize_t display_rotate_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_mirror_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int mirror;
        if (!dssdev->driver->get_mirror)
                return -ENOENT;
@@ -218,10 +185,9 @@ static ssize_t display_mirror_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
 }
 
-static ssize_t display_mirror_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool mirror;
 
@@ -239,10 +205,8 @@ static ssize_t display_mirror_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_wss_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        unsigned int wss;
 
        if (!dssdev->driver->get_wss)
@@ -253,10 +217,9 @@ static ssize_t display_wss_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
 }
 
-static ssize_t display_wss_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_wss_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        u32 wss;
        int r;
 
@@ -277,50 +240,94 @@ static ssize_t display_wss_store(struct device *dev,
        return size;
 }
 
-static DEVICE_ATTR(display_name, S_IRUGO, display_name_show, NULL);
-static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
+struct display_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct omap_dss_device *, char *);
+       ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
+};
+
+#define DISPLAY_ATTR(_name, _mode, _show, _store) \
+       struct display_attribute display_attr_##_name = \
+       __ATTR(_name, _mode, _show, _store)
+
+static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
+static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
+static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
                display_enabled_show, display_enabled_store);
-static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
                display_tear_show, display_tear_store);
-static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
                display_timings_show, display_timings_store);
-static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
                display_rotate_show, display_rotate_store);
-static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
                display_mirror_show, display_mirror_store);
-static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
                display_wss_show, display_wss_store);
 
-static const struct attribute *display_sysfs_attrs[] = {
-       &dev_attr_display_name.attr,
-       &dev_attr_enabled.attr,
-       &dev_attr_tear_elim.attr,
-       &dev_attr_timings.attr,
-       &dev_attr_rotate.attr,
-       &dev_attr_mirror.attr,
-       &dev_attr_wss.attr,
+static struct attribute *display_sysfs_attrs[] = {
+       &display_attr_name.attr,
+       &display_attr_display_name.attr,
+       &display_attr_enabled.attr,
+       &display_attr_tear_elim.attr,
+       &display_attr_timings.attr,
+       &display_attr_rotate.attr,
+       &display_attr_mirror.attr,
+       &display_attr_wss.attr,
        NULL
 };
 
+static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev;
+       struct display_attribute *display_attr;
+
+       dssdev = container_of(kobj, struct omap_dss_device, kobj);
+       display_attr = container_of(attr, struct display_attribute, attr);
+
+       if (!display_attr->show)
+               return -ENOENT;
+
+       return display_attr->show(dssdev, buf);
+}
+
+static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
+               const char *buf, size_t size)
+{
+       struct omap_dss_device *dssdev;
+       struct display_attribute *display_attr;
+
+       dssdev = container_of(kobj, struct omap_dss_device, kobj);
+       display_attr = container_of(attr, struct display_attribute, attr);
+
+       if (!display_attr->store)
+               return -ENOENT;
+
+       return display_attr->store(dssdev, buf, size);
+}
+
+static const struct sysfs_ops display_sysfs_ops = {
+       .show = display_attr_show,
+       .store = display_attr_store,
+};
+
+static struct kobj_type display_ktype = {
+       .sysfs_ops = &display_sysfs_ops,
+       .default_attrs = display_sysfs_attrs,
+};
+
 int display_init_sysfs(struct platform_device *pdev)
 {
        struct omap_dss_device *dssdev = NULL;
        int r;
 
        for_each_dss_dev(dssdev) {
-               struct kobject *kobj = &dssdev->dev->kobj;
-
-               r = sysfs_create_files(kobj, display_sysfs_attrs);
+               r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
+                       &pdev->dev.kobj, dssdev->alias);
                if (r) {
                        DSSERR("failed to create sysfs files\n");
-                       goto err;
-               }
-
-               r = sysfs_create_link(&pdev->dev.kobj, kobj, dssdev->alias);
-               if (r) {
-                       sysfs_remove_files(kobj, display_sysfs_attrs);
-
-                       DSSERR("failed to create sysfs display link\n");
+                       omap_dss_put_device(dssdev);
                        goto err;
                }
        }
@@ -338,8 +345,12 @@ void display_uninit_sysfs(struct platform_device *pdev)
        struct omap_dss_device *dssdev = NULL;
 
        for_each_dss_dev(dssdev) {
-               sysfs_remove_link(&pdev->dev.kobj, dssdev->alias);
-               sysfs_remove_files(&dssdev->dev->kobj,
-                               display_sysfs_attrs);
+               if (kobject_name(&dssdev->kobj) == NULL)
+                       continue;
+
+               kobject_del(&dssdev->kobj);
+               kobject_put(&dssdev->kobj);
+
+               memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
        }
 }
index 0413157..6a356e3 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/balloon_compaction.h>
 #include <linux/oom.h>
+#include <linux/wait.h>
 
 /*
  * Balloon device works in 4K page units.  So each page is pointed to by
@@ -334,17 +335,25 @@ static int virtballoon_oom_notify(struct notifier_block *self,
 static int balloon(void *_vballoon)
 {
        struct virtio_balloon *vb = _vballoon;
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
        set_freezable();
        while (!kthread_should_stop()) {
                s64 diff;
 
                try_to_freeze();
-               wait_event_interruptible(vb->config_change,
-                                        (diff = towards_target(vb)) != 0
-                                        || vb->need_stats_update
-                                        || kthread_should_stop()
-                                        || freezing(current));
+
+               add_wait_queue(&vb->config_change, &wait);
+               for (;;) {
+                       if ((diff = towards_target(vb)) != 0 ||
+                           vb->need_stats_update ||
+                           kthread_should_stop() ||
+                           freezing(current))
+                               break;
+                       wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+               }
+               remove_wait_queue(&vb->config_change, &wait);
+
                if (vb->need_stats_update)
                        stats_handle_request(vb);
                if (diff > 0)
@@ -499,6 +508,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
        if (err < 0)
                goto out_oom_notify;
 
+       virtio_device_ready(vdev);
+
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
                err = PTR_ERR(vb->thread);
index cad5698..6010d7e 100644 (file)
@@ -156,22 +156,95 @@ static void vm_get(struct virtio_device *vdev, unsigned offset,
                   void *buf, unsigned len)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       u8 *ptr = buf;
-       int i;
+       void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
+       u8 b;
+       __le16 w;
+       __le32 l;
 
-       for (i = 0; i < len; i++)
-               ptr[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+       if (vm_dev->version == 1) {
+               u8 *ptr = buf;
+               int i;
+
+               for (i = 0; i < len; i++)
+                       ptr[i] = readb(base + offset + i);
+               return;
+       }
+
+       switch (len) {
+       case 1:
+               b = readb(base + offset);
+               memcpy(buf, &b, sizeof b);
+               break;
+       case 2:
+               w = cpu_to_le16(readw(base + offset));
+               memcpy(buf, &w, sizeof w);
+               break;
+       case 4:
+               l = cpu_to_le32(readl(base + offset));
+               memcpy(buf, &l, sizeof l);
+               break;
+       case 8:
+               l = cpu_to_le32(readl(base + offset));
+               memcpy(buf, &l, sizeof l);
+               l = cpu_to_le32(ioread32(base + offset + sizeof l));
+               memcpy(buf + sizeof l, &l, sizeof l);
+               break;
+       default:
+               BUG();
+       }
 }
 
 static void vm_set(struct virtio_device *vdev, unsigned offset,
                   const void *buf, unsigned len)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       const u8 *ptr = buf;
-       int i;
+       void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
+       u8 b;
+       __le16 w;
+       __le32 l;
 
-       for (i = 0; i < len; i++)
-               writeb(ptr[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+       if (vm_dev->version == 1) {
+               const u8 *ptr = buf;
+               int i;
+
+               for (i = 0; i < len; i++)
+                       writeb(ptr[i], base + offset + i);
+
+               return;
+       }
+
+       switch (len) {
+       case 1:
+               memcpy(&b, buf, sizeof b);
+               writeb(b, base + offset);
+               break;
+       case 2:
+               memcpy(&w, buf, sizeof w);
+               writew(le16_to_cpu(w), base + offset);
+               break;
+       case 4:
+               memcpy(&l, buf, sizeof l);
+               writel(le32_to_cpu(l), base + offset);
+               break;
+       case 8:
+               memcpy(&l, buf, sizeof l);
+               writel(le32_to_cpu(l), base + offset);
+               memcpy(&l, buf + sizeof l, sizeof l);
+               writel(le32_to_cpu(l), base + offset + sizeof l);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static u32 vm_generation(struct virtio_device *vdev)
+{
+       struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+
+       if (vm_dev->version == 1)
+               return 0;
+       else
+               return readl(vm_dev->base + VIRTIO_MMIO_CONFIG_GENERATION);
 }
 
 static u8 vm_get_status(struct virtio_device *vdev)
@@ -440,6 +513,7 @@ static const char *vm_bus_name(struct virtio_device *vdev)
 static const struct virtio_config_ops virtio_mmio_config_ops = {
        .get            = vm_get,
        .set            = vm_set,
+       .generation     = vm_generation,
        .get_status     = vm_get_status,
        .set_status     = vm_set_status,
        .reset          = vm_reset,
index 6df9405..1443b3c 100644 (file)
@@ -208,7 +208,8 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
 
        if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) {
                err = request_irq(wdt->irq, wdt_interrupt,
-                                 IRQF_SHARED | IRQF_IRQPOLL,
+                                 IRQF_SHARED | IRQF_IRQPOLL |
+                                 IRQF_NO_SUSPEND,
                                  pdev->name, wdt);
                if (err)
                        return err;
index c8def68..0deaa4f 100644 (file)
 #define PDC_WDT_MIN_TIMEOUT            1
 #define PDC_WDT_DEF_TIMEOUT            64
 
-static int heartbeat;
+static int heartbeat = PDC_WDT_DEF_TIMEOUT;
 module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
-       "(default = " __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds "
+       "(default=" __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
@@ -191,6 +191,7 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        pdc_wdt->wdt_dev.ops = &pdc_wdt_ops;
        pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK;
        pdc_wdt->wdt_dev.parent = &pdev->dev;
+       watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
        ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
        if (ret < 0) {
@@ -232,7 +233,6 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout);
 
        platform_set_drvdata(pdev, pdc_wdt);
-       watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
        ret = watchdog_register_device(&pdc_wdt->wdt_dev);
        if (ret)
index a87f6df..938b987 100644 (file)
@@ -133,7 +133,7 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
        u32 reg;
        struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
        void __iomem *wdt_base = mtk_wdt->wdt_base;
-       u32 ret;
+       int ret;
 
        ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
        if (ret < 0)
index b812462..94d9680 100644 (file)
@@ -55,6 +55,23 @@ config XEN_BALLOON_MEMORY_HOTPLUG
 
          In that case step 3 should be omitted.
 
+config XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+       int "Hotplugged memory limit (in GiB) for a PV guest"
+       default 512 if X86_64
+       default 4 if X86_32
+       range 0 64 if X86_32
+       depends on XEN_HAVE_PVMMU
+       depends on XEN_BALLOON_MEMORY_HOTPLUG
+       help
+         Maxmium amount of memory (in GiB) that a PV guest can be
+         expanded to when using memory hotplug.
+
+         A PV guest can have more memory than this limit if is
+         started with a larger maximum.
+
+         This value is used to allocate enough space in internal
+         tables needed for physical memory administration.
+
 config XEN_SCRUB_PAGES
        bool "Scrub pages before returning them to system"
        depends on XEN_BALLOON
index 2140398..2ccd359 100644 (file)
@@ -2,7 +2,7 @@ ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 endif
 obj-$(CONFIG_X86)                      += fallback.o
-obj-y  += grant-table.o features.o balloon.o manage.o
+obj-y  += grant-table.o features.o balloon.o manage.o preempt.o
 obj-y  += events/
 obj-y  += xenbus/
 
index 0b52d92..fd93369 100644 (file)
@@ -229,6 +229,29 @@ static enum bp_state reserve_additional_memory(long credit)
        balloon_hotplug = round_up(balloon_hotplug, PAGES_PER_SECTION);
        nid = memory_add_physaddr_to_nid(hotplug_start_paddr);
 
+#ifdef CONFIG_XEN_HAVE_PVMMU
+        /*
+         * add_memory() will build page tables for the new memory so
+         * the p2m must contain invalid entries so the correct
+         * non-present PTEs will be written.
+         *
+         * If a failure occurs, the original (identity) p2m entries
+         * are not restored since this region is now known not to
+         * conflict with any devices.
+         */ 
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               unsigned long pfn, i;
+
+               pfn = PFN_DOWN(hotplug_start_paddr);
+               for (i = 0; i < balloon_hotplug; i++) {
+                       if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) {
+                               pr_warn("set_phys_to_machine() failed, no memory added\n");
+                               return BP_ECANCELED;
+                       }
+                }
+       }
+#endif
+
        rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT);
 
        if (rc) {
index b4bca2d..70fba97 100644 (file)
@@ -526,20 +526,26 @@ static unsigned int __startup_pirq(unsigned int irq)
        pirq_query_unmask(irq);
 
        rc = set_evtchn_to_irq(evtchn, irq);
-       if (rc != 0) {
-               pr_err("irq%d: Failed to set port to irq mapping (%d)\n",
-                      irq, rc);
-               xen_evtchn_close(evtchn);
-               return 0;
-       }
+       if (rc)
+               goto err;
+
        bind_evtchn_to_cpu(evtchn, 0);
        info->evtchn = evtchn;
 
+       rc = xen_evtchn_port_setup(info);
+       if (rc)
+               goto err;
+
 out:
        unmask_evtchn(evtchn);
        eoi_pirq(irq_get_irq_data(irq));
 
        return 0;
+
+err:
+       pr_err("irq%d: Failed to set port to irq mapping (%d)\n", irq, rc);
+       xen_evtchn_close(evtchn);
+       return 0;
 }
 
 static unsigned int startup_pirq(struct irq_data *data)
diff --git a/drivers/xen/preempt.c b/drivers/xen/preempt.c
new file mode 100644 (file)
index 0000000..a1800c1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Preemptible hypercalls
+ *
+ * Copyright (C) 2014 Citrix Systems R&D ltd.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <xen/xen-ops.h>
+
+#ifndef CONFIG_PREEMPT
+
+/*
+ * Some hypercalls issued by the toolstack can take many 10s of
+ * seconds. Allow tasks running hypercalls via the privcmd driver to
+ * be voluntarily preempted even if full kernel preemption is
+ * disabled.
+ *
+ * Such preemptible hypercalls are bracketed by
+ * xen_preemptible_hcall_begin() and xen_preemptible_hcall_end()
+ * calls.
+ */
+
+DEFINE_PER_CPU(bool, xen_in_preemptible_hcall);
+EXPORT_SYMBOL_GPL(xen_in_preemptible_hcall);
+
+asmlinkage __visible void xen_maybe_preempt_hcall(void)
+{
+       if (unlikely(__this_cpu_read(xen_in_preemptible_hcall)
+                    && should_resched())) {
+               /*
+                * Clear flag as we may be rescheduled on a different
+                * cpu.
+                */
+               __this_cpu_write(xen_in_preemptible_hcall, false);
+               _cond_resched();
+               __this_cpu_write(xen_in_preemptible_hcall, true);
+       }
+}
+#endif /* CONFIG_PREEMPT */
index 569a13b..59ac71c 100644 (file)
@@ -56,10 +56,12 @@ static long privcmd_ioctl_hypercall(void __user *udata)
        if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
                return -EFAULT;
 
+       xen_preemptible_hcall_begin();
        ret = privcmd_call(hypercall.op,
                           hypercall.arg[0], hypercall.arg[1],
                           hypercall.arg[2], hypercall.arg[3],
                           hypercall.arg[4]);
+       xen_preemptible_hcall_end();
 
        return ret;
 }
index 46ae0f9..75fe3d4 100644 (file)
@@ -16,7 +16,7 @@
 #include "conf_space.h"
 #include "conf_space_quirks.h"
 
-static bool permissive;
+bool permissive;
 module_param(permissive, bool, 0644);
 
 /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
index e56c934..2e1d73d 100644 (file)
@@ -64,6 +64,8 @@ struct config_field_entry {
        void *data;
 };
 
+extern bool permissive;
+
 #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
 
 /* Add fields to a device - the add_fields macro expects to get a pointer to
index c5ee825..2d73693 100644 (file)
 #include "pciback.h"
 #include "conf_space.h"
 
+struct pci_cmd_info {
+       u16 val;
+};
+
 struct pci_bar_info {
        u32 val;
        u32 len_val;
@@ -20,22 +24,36 @@ struct pci_bar_info {
 #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
 #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
 
-static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+/* Bits guests are allowed to control in permissive mode. */
+#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
+                          PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
+                          PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
+
+static void *command_init(struct pci_dev *dev, int offset)
 {
-       int i;
-       int ret;
-
-       ret = xen_pcibk_read_config_word(dev, offset, value, data);
-       if (!pci_is_enabled(dev))
-               return ret;
-
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
-               if (dev->resource[i].flags & IORESOURCE_IO)
-                       *value |= PCI_COMMAND_IO;
-               if (dev->resource[i].flags & IORESOURCE_MEM)
-                       *value |= PCI_COMMAND_MEMORY;
+       struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+       int err;
+
+       if (!cmd)
+               return ERR_PTR(-ENOMEM);
+
+       err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
+       if (err) {
+               kfree(cmd);
+               return ERR_PTR(err);
        }
 
+       return cmd;
+}
+
+static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+{
+       int ret = pci_read_config_word(dev, offset, value);
+       const struct pci_cmd_info *cmd = data;
+
+       *value &= PCI_COMMAND_GUEST;
+       *value |= cmd->val & ~PCI_COMMAND_GUEST;
+
        return ret;
 }
 
@@ -43,6 +61,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
 {
        struct xen_pcibk_dev_data *dev_data;
        int err;
+       u16 val;
+       struct pci_cmd_info *cmd = data;
 
        dev_data = pci_get_drvdata(dev);
        if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
@@ -83,6 +103,19 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
                }
        }
 
+       cmd->val = value;
+
+       if (!permissive && (!dev_data || !dev_data->permissive))
+               return 0;
+
+       /* Only allow the guest to control certain bits. */
+       err = pci_read_config_word(dev, offset, &val);
+       if (err || val == value)
+               return err;
+
+       value &= PCI_COMMAND_GUEST;
+       value |= val & ~PCI_COMMAND_GUEST;
+
        return pci_write_config_word(dev, offset, value);
 }
 
@@ -282,6 +315,8 @@ static const struct config_field header_common[] = {
        {
         .offset    = PCI_COMMAND,
         .size      = 2,
+        .init      = command_init,
+        .release   = bar_release,
         .u.w.read  = command_read,
         .u.w.write = command_write,
        },
index 61653a0..42bd55a 100644 (file)
@@ -709,12 +709,11 @@ static int prepare_pending_reqs(struct vscsibk_info *info,
 static int scsiback_do_cmd_fn(struct vscsibk_info *info)
 {
        struct vscsiif_back_ring *ring = &info->ring;
-       struct vscsiif_request *ring_req;
+       struct vscsiif_request ring_req;
        struct vscsibk_pend *pending_req;
        RING_IDX rc, rp;
        int err, more_to_do;
        uint32_t result;
-       uint8_t act;
 
        rc = ring->req_cons;
        rp = ring->sring->req_prod;
@@ -735,11 +734,10 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                if (!pending_req)
                        return 1;
 
-               ring_req = RING_GET_REQUEST(ring, rc);
+               ring_req = *RING_GET_REQUEST(ring, rc);
                ring->req_cons = ++rc;
 
-               act = ring_req->act;
-               err = prepare_pending_reqs(info, ring_req, pending_req);
+               err = prepare_pending_reqs(info, &ring_req, pending_req);
                if (err) {
                        switch (err) {
                        case -ENODEV:
@@ -755,9 +753,9 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                        return 1;
                }
 
-               switch (act) {
+               switch (ring_req.act) {
                case VSCSIIF_ACT_SCSI_CDB:
-                       if (scsiback_gnttab_data_map(ring_req, pending_req)) {
+                       if (scsiback_gnttab_data_map(&ring_req, pending_req)) {
                                scsiback_fast_flush_area(pending_req);
                                scsiback_do_resp_with_sense(NULL,
                                        DRIVER_ERROR << 24, 0, pending_req);
@@ -768,7 +766,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                        break;
                case VSCSIIF_ACT_SCSI_ABORT:
                        scsiback_device_action(pending_req, TMR_ABORT_TASK,
-                               ring_req->ref_rqid);
+                               ring_req.ref_rqid);
                        break;
                case VSCSIIF_ACT_SCSI_RESET:
                        scsiback_device_action(pending_req, TMR_LUN_RESET, 0);
@@ -1661,11 +1659,8 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg,
                         name);
                goto out;
        }
-       /*
-        * Now register the TCM pvscsi virtual I_T Nexus as active with the
-        * call to __transport_register_session()
-        */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       /* Now register the TCM pvscsi virtual I_T Nexus as active. */
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index d2468bf..a91795e 100644 (file)
@@ -699,8 +699,10 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
        boff = tmp % bsize;
        if (boff) {
                bh = affs_bread_ino(inode, bidx, 0);
-               if (IS_ERR(bh))
-                       return PTR_ERR(bh);
+               if (IS_ERR(bh)) {
+                       written = PTR_ERR(bh);
+                       goto err_first_bh;
+               }
                tmp = min(bsize - boff, to - from);
                BUG_ON(boff + tmp > bsize || tmp > bsize);
                memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
@@ -712,14 +714,16 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                bidx++;
        } else if (bidx) {
                bh = affs_bread_ino(inode, bidx - 1, 0);
-               if (IS_ERR(bh))
-                       return PTR_ERR(bh);
+               if (IS_ERR(bh)) {
+                       written = PTR_ERR(bh);
+                       goto err_first_bh;
+               }
        }
        while (from + bsize <= to) {
                prev_bh = bh;
                bh = affs_getemptyblk_ino(inode, bidx);
                if (IS_ERR(bh))
-                       goto out;
+                       goto err_bh;
                memcpy(AFFS_DATA(bh), data + from, bsize);
                if (buffer_new(bh)) {
                        AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
@@ -751,7 +755,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                prev_bh = bh;
                bh = affs_bread_ino(inode, bidx, 1);
                if (IS_ERR(bh))
-                       goto out;
+                       goto err_bh;
                tmp = min(bsize, to - from);
                BUG_ON(tmp > bsize);
                memcpy(AFFS_DATA(bh), data + from, tmp);
@@ -790,12 +794,13 @@ done:
        if (tmp > inode->i_size)
                inode->i_size = AFFS_I(inode)->mmu_private = tmp;
 
+err_first_bh:
        unlock_page(page);
        page_cache_release(page);
 
        return written;
 
-out:
+err_bh:
        bh = prev_bh;
        if (!written)
                written = PTR_ERR(bh);
index 9936421..6d67f32 100644 (file)
@@ -1645,14 +1645,14 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 
        parent_nritems = btrfs_header_nritems(parent);
        blocksize = root->nodesize;
-       end_slot = parent_nritems;
+       end_slot = parent_nritems - 1;
 
-       if (parent_nritems == 1)
+       if (parent_nritems <= 1)
                return 0;
 
        btrfs_set_lock_blocking(parent);
 
-       for (i = start_slot; i < end_slot; i++) {
+       for (i = start_slot; i <= end_slot; i++) {
                int close = 1;
 
                btrfs_node_key(parent, &disk_key, i);
@@ -1669,7 +1669,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                        other = btrfs_node_blockptr(parent, i - 1);
                        close = close_blocks(blocknr, other, blocksize);
                }
-               if (!close && i < end_slot - 2) {
+               if (!close && i < end_slot) {
                        other = btrfs_node_blockptr(parent, i + 1);
                        close = close_blocks(blocknr, other, blocksize);
                }
index 84c3b00..f9c89ca 100644 (file)
@@ -3387,6 +3387,8 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                    struct btrfs_root *root);
+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root);
 int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr);
 int btrfs_free_block_groups(struct btrfs_fs_info *info);
 int btrfs_read_block_groups(struct btrfs_root *root);
@@ -3909,6 +3911,9 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
                                    loff_t actual_len, u64 *alloc_hint);
 int btrfs_inode_check_errors(struct inode *inode);
 extern const struct dentry_operations btrfs_dentry_operations;
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+void btrfs_test_inode_set_ops(struct inode *inode);
+#endif
 
 /* ioctl.c */
 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
index f79f385..639f266 100644 (file)
@@ -3921,7 +3921,7 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
        }
        if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key)
                        + sizeof(struct btrfs_chunk)) {
-               printk(KERN_ERR "BTRFS: system chunk array too small %u < %lu\n",
+               printk(KERN_ERR "BTRFS: system chunk array too small %u < %zu\n",
                                btrfs_super_sys_array_size(sb),
                                sizeof(struct btrfs_disk_key)
                                + sizeof(struct btrfs_chunk));
index 571f402..8b353ad 100644 (file)
@@ -3208,6 +3208,8 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
                return 0;
        }
 
+       if (trans->aborted)
+               return 0;
 again:
        inode = lookup_free_space_inode(root, block_group, path);
        if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
@@ -3243,6 +3245,20 @@ again:
         */
        BTRFS_I(inode)->generation = 0;
        ret = btrfs_update_inode(trans, root, inode);
+       if (ret) {
+               /*
+                * So theoretically we could recover from this, simply set the
+                * super cache generation to 0 so we know to invalidate the
+                * cache, but then we'd have to keep track of the block groups
+                * that fail this way so we know we _have_ to reset this cache
+                * before the next commit or risk reading stale cache.  So to
+                * limit our exposure to horrible edge cases lets just abort the
+                * transaction, this only happens in really bad situations
+                * anyway.
+                */
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_put;
+       }
        WARN_ON(ret);
 
        if (i_size_read(inode) > 0) {
@@ -3309,6 +3325,32 @@ out:
        return ret;
 }
 
+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root)
+{
+       struct btrfs_block_group_cache *cache, *tmp;
+       struct btrfs_transaction *cur_trans = trans->transaction;
+       struct btrfs_path *path;
+
+       if (list_empty(&cur_trans->dirty_bgs) ||
+           !btrfs_test_opt(root, SPACE_CACHE))
+               return 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /* Could add new block groups, use _safe just in case */
+       list_for_each_entry_safe(cache, tmp, &cur_trans->dirty_bgs,
+                                dirty_list) {
+               if (cache->disk_cache_state == BTRFS_DC_CLEAR)
+                       cache_save_setup(cache, trans, path);
+       }
+
+       btrfs_free_path(path);
+       return 0;
+}
+
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root)
 {
@@ -5094,7 +5136,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        num_bytes = ALIGN(num_bytes, root->sectorsize);
 
        spin_lock(&BTRFS_I(inode)->lock);
-       BTRFS_I(inode)->outstanding_extents++;
+       nr_extents = (unsigned)div64_u64(num_bytes +
+                                        BTRFS_MAX_EXTENT_SIZE - 1,
+                                        BTRFS_MAX_EXTENT_SIZE);
+       BTRFS_I(inode)->outstanding_extents += nr_extents;
+       nr_extents = 0;
 
        if (BTRFS_I(inode)->outstanding_extents >
            BTRFS_I(inode)->reserved_extents)
@@ -5239,6 +5285,9 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
        if (dropped > 0)
                to_free += btrfs_calc_trans_metadata_size(root, dropped);
 
+       if (btrfs_test_is_dummy_root(root))
+               return;
+
        trace_btrfs_space_reservation(root->fs_info, "delalloc",
                                      btrfs_ino(inode), to_free, 0);
        if (root->fs_info->quota_enabled) {
index c7233ff..d688cfe 100644 (file)
@@ -4968,6 +4968,12 @@ static int release_extent_buffer(struct extent_buffer *eb)
 
                /* Should be safe to release our pages at this point */
                btrfs_release_extent_buffer_page(eb);
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+               if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))) {
+                       __free_extent_buffer(eb);
+                       return 1;
+               }
+#endif
                call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
                return 1;
        }
index b78bbba..30982bb 100644 (file)
@@ -1811,22 +1811,10 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
        mutex_unlock(&inode->i_mutex);
 
        /*
-        * we want to make sure fsync finds this change
-        * but we haven't joined a transaction running right now.
-        *
-        * Later on, someone is sure to update the inode and get the
-        * real transid recorded.
-        *
-        * We set last_trans now to the fs_info generation + 1,
-        * this will either be one more than the running transaction
-        * or the generation used for the next transaction if there isn't
-        * one running right now.
-        *
         * We also have to set last_sub_trans to the current log transid,
         * otherwise subsequent syncs to a file that's been synced in this
         * transaction will appear to have already occured.
         */
-       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
        BTRFS_I(inode)->last_sub_trans = root->log_transid;
        if (num_written > 0) {
                err = generic_write_sync(file, pos, num_written);
@@ -1959,25 +1947,37 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        atomic_inc(&root->log_batch);
 
        /*
-        * check the transaction that last modified this inode
-        * and see if its already been committed
-        */
-       if (!BTRFS_I(inode)->last_trans) {
-               mutex_unlock(&inode->i_mutex);
-               goto out;
-       }
-
-       /*
-        * if the last transaction that changed this file was before
-        * the current transaction, we can bail out now without any
-        * syncing
+        * If the last transaction that changed this file was before the current
+        * transaction and we have the full sync flag set in our inode, we can
+        * bail out now without any syncing.
+        *
+        * Note that we can't bail out if the full sync flag isn't set. This is
+        * because when the full sync flag is set we start all ordered extents
+        * and wait for them to fully complete - when they complete they update
+        * the inode's last_trans field through:
+        *
+        *     btrfs_finish_ordered_io() ->
+        *         btrfs_update_inode_fallback() ->
+        *             btrfs_update_inode() ->
+        *                 btrfs_set_inode_last_trans()
+        *
+        * So we are sure that last_trans is up to date and can do this check to
+        * bail out safely. For the fast path, when the full sync flag is not
+        * set in our inode, we can not do it because we start only our ordered
+        * extents and don't wait for them to complete (that is when
+        * btrfs_finish_ordered_io runs), so here at this point their last_trans
+        * value might be less than or equals to fs_info->last_trans_committed,
+        * and setting a speculative last_trans for an inode when a buffered
+        * write is made (such as fs_info->generation + 1 for example) would not
+        * be reliable since after setting the value and before fsync is called
+        * any number of transactions can start and commit (transaction kthread
+        * commits the current transaction periodically), and a transaction
+        * commit does not start nor waits for ordered extents to complete.
         */
        smp_mb();
        if (btrfs_inode_in_log(inode, root->fs_info->generation) ||
-           BTRFS_I(inode)->last_trans <=
-           root->fs_info->last_trans_committed) {
-               BTRFS_I(inode)->last_trans = 0;
-
+           (full_sync && BTRFS_I(inode)->last_trans <=
+            root->fs_info->last_trans_committed)) {
                /*
                 * We'v had everything committed since the last time we were
                 * modified so clear this flag in case it was set for whatever
@@ -2275,6 +2275,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        bool same_page;
        bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
        u64 ino_size;
+       bool truncated_page = false;
+       bool updated_inode = false;
 
        ret = btrfs_wait_ordered_range(inode, offset, len);
        if (ret)
@@ -2306,13 +2308,18 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
         * entire page.
         */
        if (same_page && len < PAGE_CACHE_SIZE) {
-               if (offset < ino_size)
+               if (offset < ino_size) {
+                       truncated_page = true;
                        ret = btrfs_truncate_page(inode, offset, len, 0);
+               } else {
+                       ret = 0;
+               }
                goto out_only_mutex;
        }
 
        /* zero back part of the first page */
        if (offset < ino_size) {
+               truncated_page = true;
                ret = btrfs_truncate_page(inode, offset, 0, 0);
                if (ret) {
                        mutex_unlock(&inode->i_mutex);
@@ -2348,6 +2355,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                if (!ret) {
                        /* zero the front end of the last page */
                        if (tail_start + tail_len < ino_size) {
+                               truncated_page = true;
                                ret = btrfs_truncate_page(inode,
                                                tail_start + tail_len, 0, 1);
                                if (ret)
@@ -2357,8 +2365,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        }
 
        if (lockend < lockstart) {
-               mutex_unlock(&inode->i_mutex);
-               return 0;
+               ret = 0;
+               goto out_only_mutex;
        }
 
        while (1) {
@@ -2506,6 +2514,7 @@ out_trans:
 
        trans->block_rsv = &root->fs_info->trans_block_rsv;
        ret = btrfs_update_inode(trans, root, inode);
+       updated_inode = true;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root);
 out_free:
@@ -2515,6 +2524,22 @@ out:
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                             &cached_state, GFP_NOFS);
 out_only_mutex:
+       if (!updated_inode && truncated_page && !ret && !err) {
+               /*
+                * If we only end up zeroing part of a page, we still need to
+                * update the inode item, so that all the time fields are
+                * updated as well as the necessary btrfs inode in memory fields
+                * for detecting, at fsync time, if the inode isn't yet in the
+                * log tree or it's there but not up to date.
+                */
+               trans = btrfs_start_transaction(root, 1);
+               if (IS_ERR(trans)) {
+                       err = PTR_ERR(trans);
+               } else {
+                       err = btrfs_update_inode(trans, root, inode);
+                       ret = btrfs_end_transaction(trans, root);
+               }
+       }
        mutex_unlock(&inode->i_mutex);
        if (ret && !err)
                err = ret;
index a85c23d..d2e732d 100644 (file)
@@ -108,6 +108,13 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
 
 static int btrfs_dirty_inode(struct inode *inode);
 
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+void btrfs_test_inode_set_ops(struct inode *inode)
+{
+       BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+}
+#endif
+
 static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
                                     struct inode *inode,  struct inode *dir,
                                     const struct qstr *qstr)
@@ -1542,30 +1549,17 @@ static void btrfs_split_extent_hook(struct inode *inode,
                u64 new_size;
 
                /*
-                * We need the largest size of the remaining extent to see if we
-                * need to add a new outstanding extent.  Think of the following
-                * case
-                *
-                * [MEAX_EXTENT_SIZEx2 - 4k][4k]
-                *
-                * The new_size would just be 4k and we'd think we had enough
-                * outstanding extents for this if we only took one side of the
-                * split, same goes for the other direction.  We need to see if
-                * the larger size still is the same amount of extents as the
-                * original size, because if it is we need to add a new
-                * outstanding extent.  But if we split up and the larger size
-                * is less than the original then we are good to go since we've
-                * already accounted for the extra extent in our original
-                * accounting.
+                * See the explanation in btrfs_merge_extent_hook, the same
+                * applies here, just in reverse.
                 */
                new_size = orig->end - split + 1;
-               if ((split - orig->start) > new_size)
-                       new_size = split - orig->start;
-
-               num_extents = div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
+               num_extents = div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
                                        BTRFS_MAX_EXTENT_SIZE);
-               if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
-                             BTRFS_MAX_EXTENT_SIZE) < num_extents)
+               new_size = split - orig->start;
+               num_extents += div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
+                                       BTRFS_MAX_EXTENT_SIZE);
+               if (div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
+                             BTRFS_MAX_EXTENT_SIZE) >= num_extents)
                        return;
        }
 
@@ -1591,8 +1585,10 @@ static void btrfs_merge_extent_hook(struct inode *inode,
        if (!(other->state & EXTENT_DELALLOC))
                return;
 
-       old_size = other->end - other->start + 1;
-       new_size = old_size + (new->end - new->start + 1);
+       if (new->start > other->start)
+               new_size = new->end - other->start + 1;
+       else
+               new_size = other->end - new->start + 1;
 
        /* we're not bigger than the max, unreserve the space and go */
        if (new_size <= BTRFS_MAX_EXTENT_SIZE) {
@@ -1603,13 +1599,32 @@ static void btrfs_merge_extent_hook(struct inode *inode,
        }
 
        /*
-        * If we grew by another max_extent, just return, we want to keep that
-        * reserved amount.
+        * We have to add up either side to figure out how many extents were
+        * accounted for before we merged into one big extent.  If the number of
+        * extents we accounted for is <= the amount we need for the new range
+        * then we can return, otherwise drop.  Think of it like this
+        *
+        * [ 4k][MAX_SIZE]
+        *
+        * So we've grown the extent by a MAX_SIZE extent, this would mean we
+        * need 2 outstanding extents, on one side we have 1 and the other side
+        * we have 1 so they are == and we can return.  But in this case
+        *
+        * [MAX_SIZE+4k][MAX_SIZE+4k]
+        *
+        * Each range on their own accounts for 2 extents, but merged together
+        * they are only 3 extents worth of accounting, so we need to drop in
+        * this case.
         */
+       old_size = other->end - other->start + 1;
        num_extents = div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
                                BTRFS_MAX_EXTENT_SIZE);
+       old_size = new->end - new->start + 1;
+       num_extents += div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
+                                BTRFS_MAX_EXTENT_SIZE);
+
        if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
-                     BTRFS_MAX_EXTENT_SIZE) > num_extents)
+                     BTRFS_MAX_EXTENT_SIZE) >= num_extents)
                return;
 
        spin_lock(&BTRFS_I(inode)->lock);
@@ -1686,6 +1701,10 @@ static void btrfs_set_bit_hook(struct inode *inode,
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
 
+               /* For sanity tests */
+               if (btrfs_test_is_dummy_root(root))
+                       return;
+
                __percpu_counter_add(&root->fs_info->delalloc_bytes, len,
                                     root->fs_info->delalloc_batch);
                spin_lock(&BTRFS_I(inode)->lock);
@@ -1741,6 +1760,10 @@ static void btrfs_clear_bit_hook(struct inode *inode,
                    root != root->fs_info->tree_root)
                        btrfs_delalloc_release_metadata(inode, len);
 
+               /* For sanity tests. */
+               if (btrfs_test_is_dummy_root(root))
+                       return;
+
                if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
                    && do_list && !(state->state & EXTENT_NORESERVE))
                        btrfs_free_reserved_data_space(inode, len);
@@ -7213,7 +7236,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        u64 start = iblock << inode->i_blkbits;
        u64 lockstart, lockend;
        u64 len = bh_result->b_size;
-       u64 orig_len = len;
+       u64 *outstanding_extents = NULL;
        int unlock_bits = EXTENT_LOCKED;
        int ret = 0;
 
@@ -7225,6 +7248,16 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        lockstart = start;
        lockend = start + len - 1;
 
+       if (current->journal_info) {
+               /*
+                * Need to pull our outstanding extents and set journal_info to NULL so
+                * that anything that needs to check if there's a transction doesn't get
+                * confused.
+                */
+               outstanding_extents = current->journal_info;
+               current->journal_info = NULL;
+       }
+
        /*
         * If this errors out it's because we couldn't invalidate pagecache for
         * this range and we need to fallback to buffered.
@@ -7285,7 +7318,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
            ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) &&
             em->block_start != EXTENT_MAP_HOLE)) {
                int type;
-               int ret;
                u64 block_start, orig_start, orig_block_len, ram_bytes;
 
                if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
@@ -7349,11 +7381,20 @@ unlock:
                if (start + len > i_size_read(inode))
                        i_size_write(inode, start + len);
 
-               if (len < orig_len) {
+               /*
+                * If we have an outstanding_extents count still set then we're
+                * within our reservation, otherwise we need to adjust our inode
+                * counter appropriately.
+                */
+               if (*outstanding_extents) {
+                       (*outstanding_extents)--;
+               } else {
                        spin_lock(&BTRFS_I(inode)->lock);
                        BTRFS_I(inode)->outstanding_extents++;
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
+
+               current->journal_info = outstanding_extents;
                btrfs_free_reserved_data_space(inode, len);
        }
 
@@ -7377,6 +7418,8 @@ unlock:
 unlock_err:
        clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                         unlock_bits, 1, 0, &cached_state, GFP_NOFS);
+       if (outstanding_extents)
+               current->journal_info = outstanding_extents;
        return ret;
 }
 
@@ -8076,6 +8119,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       u64 outstanding_extents = 0;
        size_t count = 0;
        int flags = 0;
        bool wakeup = true;
@@ -8113,6 +8157,16 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                ret = btrfs_delalloc_reserve_space(inode, count);
                if (ret)
                        goto out;
+               outstanding_extents = div64_u64(count +
+                                               BTRFS_MAX_EXTENT_SIZE - 1,
+                                               BTRFS_MAX_EXTENT_SIZE);
+
+               /*
+                * We need to know how many extents we reserved so that we can
+                * do the accounting properly if we go over the number we
+                * originally calculated.  Abuse current->journal_info for this.
+                */
+               current->journal_info = &outstanding_extents;
        } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
                                     &BTRFS_I(inode)->runtime_flags)) {
                inode_dio_done(inode);
@@ -8125,6 +8179,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                        iter, offset, btrfs_get_blocks_direct, NULL,
                        btrfs_submit_direct, flags);
        if (rw & WRITE) {
+               current->journal_info = NULL;
                if (ret < 0 && ret != -EIOCBQUEUED)
                        btrfs_delalloc_release_space(inode, count);
                else if (ret >= 0 && (size_t)ret < count)
index 534544e..157cc54 100644 (file)
@@ -452,9 +452,7 @@ void btrfs_get_logged_extents(struct inode *inode,
                        continue;
                if (entry_end(ordered) <= start)
                        break;
-               if (!list_empty(&ordered->log_list))
-                       continue;
-               if (test_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
+               if (test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
                        continue;
                list_add(&ordered->log_list, logged_list);
                atomic_inc(&ordered->refs);
@@ -511,8 +509,7 @@ void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans,
                wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE,
                                                   &ordered->flags));
 
-               if (!test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
-                       list_add_tail(&ordered->trans_list, &trans->ordered);
+               list_add_tail(&ordered->trans_list, &trans->ordered);
                spin_lock_irq(&log->log_extents_lock[index]);
        }
        spin_unlock_irq(&log->log_extents_lock[index]);
index 97159a8..058c79e 100644 (file)
@@ -1259,7 +1259,7 @@ static int comp_oper(struct btrfs_qgroup_operation *oper1,
        if (oper1->seq < oper2->seq)
                return -1;
        if (oper1->seq > oper2->seq)
-               return -1;
+               return 1;
        if (oper1->ref_root < oper2->ref_root)
                return -1;
        if (oper1->ref_root > oper2->ref_root)
index fe58572..d6033f5 100644 (file)
@@ -230,6 +230,7 @@ struct pending_dir_move {
        u64 parent_ino;
        u64 ino;
        u64 gen;
+       bool is_orphan;
        struct list_head update_refs;
 };
 
@@ -2984,7 +2985,8 @@ static int add_pending_dir_move(struct send_ctx *sctx,
                                u64 ino_gen,
                                u64 parent_ino,
                                struct list_head *new_refs,
-                               struct list_head *deleted_refs)
+                               struct list_head *deleted_refs,
+                               const bool is_orphan)
 {
        struct rb_node **p = &sctx->pending_dir_moves.rb_node;
        struct rb_node *parent = NULL;
@@ -2999,6 +3001,7 @@ static int add_pending_dir_move(struct send_ctx *sctx,
        pm->parent_ino = parent_ino;
        pm->ino = ino;
        pm->gen = ino_gen;
+       pm->is_orphan = is_orphan;
        INIT_LIST_HEAD(&pm->list);
        INIT_LIST_HEAD(&pm->update_refs);
        RB_CLEAR_NODE(&pm->node);
@@ -3131,16 +3134,20 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
        rmdir_ino = dm->rmdir_ino;
        free_waiting_dir_move(sctx, dm);
 
-       ret = get_first_ref(sctx->parent_root, pm->ino,
-                           &parent_ino, &parent_gen, name);
-       if (ret < 0)
-               goto out;
-
-       ret = get_cur_path(sctx, parent_ino, parent_gen,
-                          from_path);
-       if (ret < 0)
-               goto out;
-       ret = fs_path_add_path(from_path, name);
+       if (pm->is_orphan) {
+               ret = gen_unique_name(sctx, pm->ino,
+                                     pm->gen, from_path);
+       } else {
+               ret = get_first_ref(sctx->parent_root, pm->ino,
+                                   &parent_ino, &parent_gen, name);
+               if (ret < 0)
+                       goto out;
+               ret = get_cur_path(sctx, parent_ino, parent_gen,
+                                  from_path);
+               if (ret < 0)
+                       goto out;
+               ret = fs_path_add_path(from_path, name);
+       }
        if (ret < 0)
                goto out;
 
@@ -3150,7 +3157,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
                LIST_HEAD(deleted_refs);
                ASSERT(ancestor > BTRFS_FIRST_FREE_OBJECTID);
                ret = add_pending_dir_move(sctx, pm->ino, pm->gen, ancestor,
-                                          &pm->update_refs, &deleted_refs);
+                                          &pm->update_refs, &deleted_refs,
+                                          pm->is_orphan);
                if (ret < 0)
                        goto out;
                if (rmdir_ino) {
@@ -3283,6 +3291,127 @@ out:
        return ret;
 }
 
+/*
+ * We might need to delay a directory rename even when no ancestor directory
+ * (in the send root) with a higher inode number than ours (sctx->cur_ino) was
+ * renamed. This happens when we rename a directory to the old name (the name
+ * in the parent root) of some other unrelated directory that got its rename
+ * delayed due to some ancestor with higher number that got renamed.
+ *
+ * Example:
+ *
+ * Parent snapshot:
+ * .                                       (ino 256)
+ * |---- a/                                (ino 257)
+ * |     |---- file                        (ino 260)
+ * |
+ * |---- b/                                (ino 258)
+ * |---- c/                                (ino 259)
+ *
+ * Send snapshot:
+ * .                                       (ino 256)
+ * |---- a/                                (ino 258)
+ * |---- x/                                (ino 259)
+ *       |---- y/                          (ino 257)
+ *             |----- file                 (ino 260)
+ *
+ * Here we can not rename 258 from 'b' to 'a' without the rename of inode 257
+ * from 'a' to 'x/y' happening first, which in turn depends on the rename of
+ * inode 259 from 'c' to 'x'. So the order of rename commands the send stream
+ * must issue is:
+ *
+ * 1 - rename 259 from 'c' to 'x'
+ * 2 - rename 257 from 'a' to 'x/y'
+ * 3 - rename 258 from 'b' to 'a'
+ *
+ * Returns 1 if the rename of sctx->cur_ino needs to be delayed, 0 if it can
+ * be done right away and < 0 on error.
+ */
+static int wait_for_dest_dir_move(struct send_ctx *sctx,
+                                 struct recorded_ref *parent_ref,
+                                 const bool is_orphan)
+{
+       struct btrfs_path *path;
+       struct btrfs_key key;
+       struct btrfs_key di_key;
+       struct btrfs_dir_item *di;
+       u64 left_gen;
+       u64 right_gen;
+       int ret = 0;
+
+       if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves))
+               return 0;
+
+       path = alloc_path_for_send();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = parent_ref->dir;
+       key.type = BTRFS_DIR_ITEM_KEY;
+       key.offset = btrfs_name_hash(parent_ref->name, parent_ref->name_len);
+
+       ret = btrfs_search_slot(NULL, sctx->parent_root, &key, path, 0, 0);
+       if (ret < 0) {
+               goto out;
+       } else if (ret > 0) {
+               ret = 0;
+               goto out;
+       }
+
+       di = btrfs_match_dir_item_name(sctx->parent_root, path,
+                                      parent_ref->name, parent_ref->name_len);
+       if (!di) {
+               ret = 0;
+               goto out;
+       }
+       /*
+        * di_key.objectid has the number of the inode that has a dentry in the
+        * parent directory with the same name that sctx->cur_ino is being
+        * renamed to. We need to check if that inode is in the send root as
+        * well and if it is currently marked as an inode with a pending rename,
+        * if it is, we need to delay the rename of sctx->cur_ino as well, so
+        * that it happens after that other inode is renamed.
+        */
+       btrfs_dir_item_key_to_cpu(path->nodes[0], di, &di_key);
+       if (di_key.type != BTRFS_INODE_ITEM_KEY) {
+               ret = 0;
+               goto out;
+       }
+
+       ret = get_inode_info(sctx->parent_root, di_key.objectid, NULL,
+                            &left_gen, NULL, NULL, NULL, NULL);
+       if (ret < 0)
+               goto out;
+       ret = get_inode_info(sctx->send_root, di_key.objectid, NULL,
+                            &right_gen, NULL, NULL, NULL, NULL);
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       ret = 0;
+               goto out;
+       }
+
+       /* Different inode, no need to delay the rename of sctx->cur_ino */
+       if (right_gen != left_gen) {
+               ret = 0;
+               goto out;
+       }
+
+       if (is_waiting_for_move(sctx, di_key.objectid)) {
+               ret = add_pending_dir_move(sctx,
+                                          sctx->cur_ino,
+                                          sctx->cur_inode_gen,
+                                          di_key.objectid,
+                                          &sctx->new_refs,
+                                          &sctx->deleted_refs,
+                                          is_orphan);
+               if (!ret)
+                       ret = 1;
+       }
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 static int wait_for_parent_move(struct send_ctx *sctx,
                                struct recorded_ref *parent_ref)
 {
@@ -3349,7 +3478,8 @@ out:
                                           sctx->cur_inode_gen,
                                           ino,
                                           &sctx->new_refs,
-                                          &sctx->deleted_refs);
+                                          &sctx->deleted_refs,
+                                          false);
                if (!ret)
                        ret = 1;
        }
@@ -3372,6 +3502,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
        int did_overwrite = 0;
        int is_orphan = 0;
        u64 last_dir_ino_rm = 0;
+       bool can_rename = true;
 
 verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
 
@@ -3490,12 +3621,22 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                        }
                }
 
+               if (S_ISDIR(sctx->cur_inode_mode) && sctx->parent_root) {
+                       ret = wait_for_dest_dir_move(sctx, cur, is_orphan);
+                       if (ret < 0)
+                               goto out;
+                       if (ret == 1) {
+                               can_rename = false;
+                               *pending_move = 1;
+                       }
+               }
+
                /*
                 * link/move the ref to the new place. If we have an orphan
                 * inode, move it and update valid_path. If not, link or move
                 * it depending on the inode mode.
                 */
-               if (is_orphan) {
+               if (is_orphan && can_rename) {
                        ret = send_rename(sctx, valid_path, cur->full_path);
                        if (ret < 0)
                                goto out;
@@ -3503,7 +3644,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                        ret = fs_path_copy(valid_path, cur->full_path);
                        if (ret < 0)
                                goto out;
-               } else {
+               } else if (can_rename) {
                        if (S_ISDIR(sctx->cur_inode_mode)) {
                                /*
                                 * Dirs can't be linked, so move it. For moved
index a116b55..054fc0d 100644 (file)
@@ -911,6 +911,197 @@ out:
        return ret;
 }
 
+static int test_extent_accounting(void)
+{
+       struct inode *inode = NULL;
+       struct btrfs_root *root = NULL;
+       int ret = -ENOMEM;
+
+       inode = btrfs_new_test_inode();
+       if (!inode) {
+               test_msg("Couldn't allocate inode\n");
+               return ret;
+       }
+
+       root = btrfs_alloc_dummy_root();
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate root\n");
+               goto out;
+       }
+
+       root->fs_info = btrfs_alloc_dummy_fs_info();
+       if (!root->fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
+               goto out;
+       }
+
+       BTRFS_I(inode)->root = root;
+       btrfs_test_inode_set_ops(inode);
+
+       /* [BTRFS_MAX_EXTENT_SIZE] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, 0, BTRFS_MAX_EXTENT_SIZE - 1,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 1) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 1, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE][4k] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE,
+                                       BTRFS_MAX_EXTENT_SIZE + 4095, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE/2][4K HOLE][the rest] */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
+                              BTRFS_MAX_EXTENT_SIZE >> 1,
+                              (BTRFS_MAX_EXTENT_SIZE >> 1) + 4095,
+                              EXTENT_DELALLOC | EXTENT_DIRTY |
+                              EXTENT_UPTODATE | EXTENT_DO_ACCOUNTING, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE][4K] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE >> 1,
+                                       (BTRFS_MAX_EXTENT_SIZE >> 1) + 4095,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /*
+        * [BTRFS_MAX_EXTENT_SIZE+4K][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4K]
+        *
+        * I'm artificially adding 2 to outstanding_extents because in the
+        * buffered IO case we'd add things up as we go, but I don't feel like
+        * doing that here, this isn't the interesting case we want to test.
+        */
+       BTRFS_I(inode)->outstanding_extents += 2;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE + 8192,
+                                       (BTRFS_MAX_EXTENT_SIZE << 1) + 12287,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 4) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 4, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE+4k][4k][BTRFS_MAX_EXTENT_SIZE+4k] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE+4096,
+                                       BTRFS_MAX_EXTENT_SIZE+8191, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 3) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 3, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE+4k][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4k] */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
+                              BTRFS_MAX_EXTENT_SIZE+4096,
+                              BTRFS_MAX_EXTENT_SIZE+8191,
+                              EXTENT_DIRTY | EXTENT_DELALLOC |
+                              EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 4) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 4, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /*
+        * Refill the hole again just for good measure, because I thought it
+        * might fail and I'd rather satisfy my paranoia at this point.
+        */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE+4096,
+                                       BTRFS_MAX_EXTENT_SIZE+8191, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 3) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 3, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* Empty */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                              EXTENT_DIRTY | EXTENT_DELALLOC |
+                              EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 0, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+       ret = 0;
+out:
+       if (ret)
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                                EXTENT_DIRTY | EXTENT_DELALLOC |
+                                EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                                NULL, GFP_NOFS);
+       iput(inode);
+       btrfs_free_dummy_root(root);
+       return ret;
+}
+
 int btrfs_test_inodes(void)
 {
        int ret;
@@ -924,5 +1115,9 @@ int btrfs_test_inodes(void)
        if (ret)
                return ret;
        test_msg("Running hole first btrfs_get_extent test\n");
-       return test_hole_first();
+       ret = test_hole_first();
+       if (ret)
+               return ret;
+       test_msg("Running outstanding_extents tests\n");
+       return test_extent_accounting();
 }
index 7e80f32..8be4278 100644 (file)
@@ -1023,17 +1023,13 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
        u64 old_root_bytenr;
        u64 old_root_used;
        struct btrfs_root *tree_root = root->fs_info->tree_root;
-       bool extent_root = (root->objectid == BTRFS_EXTENT_TREE_OBJECTID);
 
        old_root_used = btrfs_root_used(&root->root_item);
-       btrfs_write_dirty_block_groups(trans, root);
 
        while (1) {
                old_root_bytenr = btrfs_root_bytenr(&root->root_item);
                if (old_root_bytenr == root->node->start &&
-                   old_root_used == btrfs_root_used(&root->root_item) &&
-                   (!extent_root ||
-                    list_empty(&trans->transaction->dirty_bgs)))
+                   old_root_used == btrfs_root_used(&root->root_item))
                        break;
 
                btrfs_set_root_node(&root->root_item, root->node);
@@ -1044,17 +1040,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                        return ret;
 
                old_root_used = btrfs_root_used(&root->root_item);
-               if (extent_root) {
-                       ret = btrfs_write_dirty_block_groups(trans, root);
-                       if (ret)
-                               return ret;
-               }
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               if (ret)
-                       return ret;
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               if (ret)
-                       return ret;
        }
 
        return 0;
@@ -1071,6 +1056,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                                         struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
+       struct list_head *dirty_bgs = &trans->transaction->dirty_bgs;
        struct list_head *next;
        struct extent_buffer *eb;
        int ret;
@@ -1098,11 +1084,15 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
        if (ret)
                return ret;
 
+       ret = btrfs_setup_space_cache(trans, root);
+       if (ret)
+               return ret;
+
        /* run_qgroups might have added some more refs */
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        if (ret)
                return ret;
-
+again:
        while (!list_empty(&fs_info->dirty_cowonly_roots)) {
                next = fs_info->dirty_cowonly_roots.next;
                list_del_init(next);
@@ -1115,8 +1105,23 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                ret = update_cowonly_root(trans, root);
                if (ret)
                        return ret;
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               if (ret)
+                       return ret;
        }
 
+       while (!list_empty(dirty_bgs)) {
+               ret = btrfs_write_dirty_block_groups(trans, root);
+               if (ret)
+                       return ret;
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               if (ret)
+                       return ret;
+       }
+
+       if (!list_empty(&fs_info->dirty_cowonly_roots))
+               goto again;
+
        list_add_tail(&fs_info->extent_root->dirty_list,
                      &trans->transaction->switch_commits);
        btrfs_after_dev_replace_commit(fs_info);
@@ -1814,6 +1819,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                wait_for_commit(root, cur_trans);
 
+               if (unlikely(cur_trans->aborted))
+                       ret = cur_trans->aborted;
+
                btrfs_put_transaction(cur_trans);
 
                return ret;
index 9a37f8b..c5b8ba3 100644 (file)
@@ -1012,7 +1012,7 @@ again:
                base = btrfs_item_ptr_offset(leaf, path->slots[0]);
 
                while (cur_offset < item_size) {
-                       extref = (struct btrfs_inode_extref *)base + cur_offset;
+                       extref = (struct btrfs_inode_extref *)(base + cur_offset);
 
                        victim_name_len = btrfs_inode_extref_name_len(leaf, extref);
 
index cd4d131..8222f6f 100644 (file)
@@ -4903,10 +4903,17 @@ static void sort_parity_stripes(struct btrfs_bio *bbio, int num_stripes)
 static struct btrfs_bio *alloc_btrfs_bio(int total_stripes, int real_stripes)
 {
        struct btrfs_bio *bbio = kzalloc(
+                /* the size of the btrfs_bio */
                sizeof(struct btrfs_bio) +
+               /* plus the variable array for the stripes */
                sizeof(struct btrfs_bio_stripe) * (total_stripes) +
+               /* plus the variable array for the tgt dev */
                sizeof(int) * (real_stripes) +
-               sizeof(u64) * (real_stripes),
+               /*
+                * plus the raid_map, which includes both the tgt dev
+                * and the stripes
+                */
+               sizeof(u64) * (total_stripes),
                GFP_NOFS);
        if (!bbio)
                return NULL;
index 47b1946..883b936 100644 (file)
@@ -111,6 +111,8 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
                                        name, name_len, -1);
                if (!di && (flags & XATTR_REPLACE))
                        ret = -ENODATA;
+               else if (IS_ERR(di))
+                       ret = PTR_ERR(di);
                else if (di)
                        ret = btrfs_delete_one_dir_name(trans, root, path, di);
                goto out;
@@ -127,10 +129,12 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
                ASSERT(mutex_is_locked(&inode->i_mutex));
                di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode),
                                        name, name_len, 0);
-               if (!di) {
+               if (!di)
                        ret = -ENODATA;
+               else if (IS_ERR(di))
+                       ret = PTR_ERR(di);
+               if (ret)
                        goto out;
-               }
                btrfs_release_path(path);
                di = NULL;
        }
index 4ac7445..aa0dc25 100644 (file)
@@ -1,6 +1,9 @@
 /*
  *   fs/cifs/cifsencrypt.c
  *
+ *   Encryption and hashing operations relating to NTLM, NTLMv2.  See MS-NLMP
+ *   for more detailed information
+ *
  *   Copyright (C) International Business Machines  Corp., 2005,2013
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
@@ -515,7 +518,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                                 __func__);
                        return rc;
                }
-       } else if (ses->serverName) {
+       } else {
+               /* We use ses->serverName if no domain name available */
                len = strlen(ses->serverName);
 
                server = kmalloc(2 + (len * 2), GFP_KERNEL);
index d3aa999..480cf9c 100644 (file)
@@ -1599,6 +1599,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                pr_warn("CIFS: username too long\n");
                                goto cifs_parse_mount_err;
                        }
+
+                       kfree(vol->username);
                        vol->username = kstrdup(string, GFP_KERNEL);
                        if (!vol->username)
                                goto cifs_parse_mount_err;
@@ -1700,6 +1702,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                goto cifs_parse_mount_err;
                        }
 
+                       kfree(vol->domainname);
                        vol->domainname = kstrdup(string, GFP_KERNEL);
                        if (!vol->domainname) {
                                pr_warn("CIFS: no memory for domainname\n");
@@ -1731,6 +1734,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        }
 
                         if (strncasecmp(string, "default", 7) != 0) {
+                               kfree(vol->iocharset);
                                vol->iocharset = kstrdup(string,
                                                         GFP_KERNEL);
                                if (!vol->iocharset) {
@@ -2913,8 +2917,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
                 * calling name ends in null (byte 16) from old smb
                 * convention.
                 */
-               if (server->workstation_RFC1001_name &&
-                   server->workstation_RFC1001_name[0] != 0)
+               if (server->workstation_RFC1001_name[0] != 0)
                        rfc1002mangle(ses_init_buf->trailer.
                                      session_req.calling_name,
                                      server->workstation_RFC1001_name,
@@ -3692,6 +3695,12 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
 #endif /* CIFS_WEAK_PW_HASH */
                rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
                                        bcc_ptr, nls_codepage);
+               if (rc) {
+                       cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n",
+                                __func__, rc);
+                       cifs_buf_release(smb_buffer);
+                       return rc;
+               }
 
                bcc_ptr += CIFS_AUTH_RESP_SIZE;
                if (ses->capabilities & CAP_UNICODE) {
index a94b3e6..ca30c39 100644 (file)
@@ -1823,6 +1823,7 @@ refind_writable:
                        cifsFileInfo_put(inv_file);
                        spin_lock(&cifs_file_list_lock);
                        ++refind;
+                       inv_file = NULL;
                        goto refind_writable;
                }
        }
index 2d4f372..3e126d7 100644 (file)
@@ -771,6 +771,8 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
                                cifs_buf_release(srchinf->ntwrk_buf_start);
                        }
                        kfree(srchinf);
+                       if (rc)
+                               goto cgii_exit;
        } else
                goto cgii_exit;
 
index 689f035..22dfdf1 100644 (file)
@@ -322,7 +322,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 
        /* return pointer to beginning of data area, ie offset from SMB start */
        if ((*off != 0) && (*len != 0))
-               return hdr->ProtocolId + *off;
+               return (char *)(&hdr->ProtocolId[0]) + *off;
        else
                return NULL;
 }
index 96b5d40..eab05e1 100644 (file)
@@ -684,7 +684,8 @@ smb2_clone_range(const unsigned int xid,
 
                        /* No need to change MaxChunks since already set to 1 */
                        chunk_sizes_updated = true;
-               }
+               } else
+                       goto cchunk_out;
        }
 
 cchunk_out:
index 3417340..65cd7a8 100644 (file)
@@ -1218,7 +1218,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        struct smb2_ioctl_req *req;
        struct smb2_ioctl_rsp *rsp;
        struct TCP_Server_Info *server;
-       struct cifs_ses *ses = tcon->ses;
+       struct cifs_ses *ses;
        struct kvec iov[2];
        int resp_buftype;
        int num_iovecs;
@@ -1233,6 +1233,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        if (plen)
                *plen = 0;
 
+       if (tcon)
+               ses = tcon->ses;
+       else
+               return -EIO;
+
        if (ses && (ses->server))
                server = ses->server;
        else
@@ -1296,14 +1301,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
 
        if ((rc != 0) && (rc != -EINVAL)) {
-               if (tcon)
-                       cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+               cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
                goto ioctl_exit;
        } else if (rc == -EINVAL) {
                if ((opcode != FSCTL_SRV_COPYCHUNK_WRITE) &&
                    (opcode != FSCTL_SRV_COPYCHUNK)) {
-                       if (tcon)
-                               cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+                       cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
                        goto ioctl_exit;
                }
        }
@@ -1629,7 +1632,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 
        rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
 
-       if ((rc != 0) && tcon)
+       if (rc != 0)
                cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
 
        free_rsp_buf(resp_buftype, iov[0].iov_base);
@@ -2114,7 +2117,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        struct kvec iov[2];
        int rc = 0;
        int len;
-       int resp_buftype;
+       int resp_buftype = CIFS_NO_BUFFER;
        unsigned char *bufptr;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
index 90d1882..5ba029e 100644 (file)
@@ -124,7 +124,7 @@ ecryptfs_get_key_payload_data(struct key *key)
 }
 
 #define ECRYPTFS_MAX_KEYSET_SIZE 1024
-#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
+#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 31
 #define ECRYPTFS_MAX_NUM_ENC_KEYS 64
 #define ECRYPTFS_MAX_IV_BYTES 16       /* 128 bits */
 #define ECRYPTFS_SALT_BYTES 2
@@ -237,7 +237,7 @@ struct ecryptfs_crypt_stat {
        struct crypto_ablkcipher *tfm;
        struct crypto_hash *hash_tfm; /* Crypto context for generating
                                       * the initialization vectors */
-       unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+       unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
        unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
        unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
        struct list_head keysig_list;
index b07731e..fd39bad 100644 (file)
@@ -303,9 +303,22 @@ ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct file *lower_file = ecryptfs_file_to_lower(file);
        long rc = -ENOTTY;
 
-       if (lower_file->f_op->unlocked_ioctl)
+       if (!lower_file->f_op->unlocked_ioctl)
+               return rc;
+
+       switch (cmd) {
+       case FITRIM:
+       case FS_IOC_GETFLAGS:
+       case FS_IOC_SETFLAGS:
+       case FS_IOC_GETVERSION:
+       case FS_IOC_SETVERSION:
                rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
-       return rc;
+               fsstack_copy_attr_all(file_inode(file), file_inode(lower_file));
+
+               return rc;
+       default:
+               return rc;
+       }
 }
 
 #ifdef CONFIG_COMPAT
@@ -315,9 +328,22 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct file *lower_file = ecryptfs_file_to_lower(file);
        long rc = -ENOIOCTLCMD;
 
-       if (lower_file->f_op->compat_ioctl)
+       if (!lower_file->f_op->compat_ioctl)
+               return rc;
+
+       switch (cmd) {
+       case FITRIM:
+       case FS_IOC32_GETFLAGS:
+       case FS_IOC32_SETFLAGS:
+       case FS_IOC32_GETVERSION:
+       case FS_IOC32_SETVERSION:
                rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
-       return rc;
+               fsstack_copy_attr_all(file_inode(file), file_inode(lower_file));
+
+               return rc;
+       default:
+               return rc;
+       }
 }
 #endif
 
index 917bd5c..6bd67e2 100644 (file)
@@ -891,7 +891,7 @@ struct ecryptfs_parse_tag_70_packet_silly_stack {
        struct blkcipher_desc desc;
        char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
        char iv[ECRYPTFS_MAX_IV_BYTES];
-       char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+       char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
 };
 
 /**
index 1895d60..c095d32 100644 (file)
@@ -407,7 +407,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
        if (!cipher_name_set) {
                int cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
 
-               BUG_ON(cipher_name_len >= ECRYPTFS_MAX_CIPHER_NAME_SIZE);
+               BUG_ON(cipher_name_len > ECRYPTFS_MAX_CIPHER_NAME_SIZE);
                strcpy(mount_crypt_stat->global_default_cipher_name,
                       ECRYPTFS_DEFAULT_CIPHER);
        }
index e907052..32a8bbd 100644 (file)
@@ -53,6 +53,18 @@ struct wb_writeback_work {
        struct completion *done;        /* set if the caller waits */
 };
 
+/*
+ * If an inode is constantly having its pages dirtied, but then the
+ * updates stop dirtytime_expire_interval seconds in the past, it's
+ * possible for the worst case time between when an inode has its
+ * timestamps updated and when they finally get written out to be two
+ * dirtytime_expire_intervals.  We set the default to 12 hours (in
+ * seconds), which means most of the time inodes will have their
+ * timestamps written to disk after 12 hours, but in the worst case a
+ * few inodes might not their timestamps updated for 24 hours.
+ */
+unsigned int dirtytime_expire_interval = 12 * 60 * 60;
+
 /**
  * writeback_in_progress - determine whether there is writeback in progress
  * @bdi: the device's backing_dev_info structure.
@@ -275,8 +287,8 @@ static int move_expired_inodes(struct list_head *delaying_queue,
 
        if ((flags & EXPIRE_DIRTY_ATIME) == 0)
                older_than_this = work->older_than_this;
-       else if ((work->reason == WB_REASON_SYNC) == 0) {
-               expire_time = jiffies - (HZ * 86400);
+       else if (!work->for_sync) {
+               expire_time = jiffies - (dirtytime_expire_interval * HZ);
                older_than_this = &expire_time;
        }
        while (!list_empty(delaying_queue)) {
@@ -458,6 +470,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
                 */
                redirty_tail(inode, wb);
        } else if (inode->i_state & I_DIRTY_TIME) {
+               inode->dirtied_when = jiffies;
                list_move(&inode->i_wb_list, &wb->b_dirty_time);
        } else {
                /* The inode is clean. Remove from writeback lists. */
@@ -505,12 +518,17 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        spin_lock(&inode->i_lock);
 
        dirty = inode->i_state & I_DIRTY;
-       if (((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) &&
-            (inode->i_state & I_DIRTY_TIME)) ||
-           (inode->i_state & I_DIRTY_TIME_EXPIRED)) {
-               dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
-               trace_writeback_lazytime(inode);
-       }
+       if (inode->i_state & I_DIRTY_TIME) {
+               if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
+                   unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) ||
+                   unlikely(time_after(jiffies,
+                                       (inode->dirtied_time_when +
+                                        dirtytime_expire_interval * HZ)))) {
+                       dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
+                       trace_writeback_lazytime(inode);
+               }
+       } else
+               inode->i_state &= ~I_DIRTY_TIME_EXPIRED;
        inode->i_state &= ~dirty;
 
        /*
@@ -1131,6 +1149,56 @@ void wakeup_flusher_threads(long nr_pages, enum wb_reason reason)
        rcu_read_unlock();
 }
 
+/*
+ * Wake up bdi's periodically to make sure dirtytime inodes gets
+ * written back periodically.  We deliberately do *not* check the
+ * b_dirtytime list in wb_has_dirty_io(), since this would cause the
+ * kernel to be constantly waking up once there are any dirtytime
+ * inodes on the system.  So instead we define a separate delayed work
+ * function which gets called much more rarely.  (By default, only
+ * once every 12 hours.)
+ *
+ * If there is any other write activity going on in the file system,
+ * this function won't be necessary.  But if the only thing that has
+ * happened on the file system is a dirtytime inode caused by an atime
+ * update, we need this infrastructure below to make sure that inode
+ * eventually gets pushed out to disk.
+ */
+static void wakeup_dirtytime_writeback(struct work_struct *w);
+static DECLARE_DELAYED_WORK(dirtytime_work, wakeup_dirtytime_writeback);
+
+static void wakeup_dirtytime_writeback(struct work_struct *w)
+{
+       struct backing_dev_info *bdi;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
+               if (list_empty(&bdi->wb.b_dirty_time))
+                       continue;
+               bdi_wakeup_thread(bdi);
+       }
+       rcu_read_unlock();
+       schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
+}
+
+static int __init start_dirtytime_writeback(void)
+{
+       schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
+       return 0;
+}
+__initcall(start_dirtytime_writeback);
+
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+                              void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       if (ret == 0 && write)
+               mod_delayed_work(system_wq, &dirtytime_work, 0);
+       return ret;
+}
+
 static noinline void block_dump___mark_inode_dirty(struct inode *inode)
 {
        if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) {
@@ -1269,8 +1337,13 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                        }
 
                        inode->dirtied_when = jiffies;
-                       list_move(&inode->i_wb_list, dirtytime ?
-                                 &bdi->wb.b_dirty_time : &bdi->wb.b_dirty);
+                       if (dirtytime)
+                               inode->dirtied_time_when = jiffies;
+                       if (inode->i_state & (I_DIRTY_INODE | I_DIRTY_PAGES))
+                               list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
+                       else
+                               list_move(&inode->i_wb_list,
+                                         &bdi->wb.b_dirty_time);
                        spin_unlock(&bdi->wb.list_lock);
                        trace_writeback_dirty_inode_enqueue(inode);
 
index ed19a7d..39706c5 100644 (file)
@@ -890,8 +890,8 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 
        newpage = buf->page;
 
-       if (WARN_ON(!PageUptodate(newpage)))
-               return -EIO;
+       if (!PageUptodate(newpage))
+               SetPageUptodate(newpage);
 
        ClearPageMappedToDisk(newpage);
 
@@ -1353,6 +1353,17 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
        return err;
 }
 
+static int fuse_dev_open(struct inode *inode, struct file *file)
+{
+       /*
+        * The fuse device's file's private_data is used to hold
+        * the fuse_conn(ection) when it is mounted, and is used to
+        * keep track of whether the file has been mounted already.
+        */
+       file->private_data = NULL;
+       return 0;
+}
+
 static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
                              unsigned long nr_segs, loff_t pos)
 {
@@ -1797,6 +1808,9 @@ copy_finish:
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
                       unsigned int size, struct fuse_copy_state *cs)
 {
+       /* Don't try to move pages (yet) */
+       cs->move_pages = 0;
+
        switch (code) {
        case FUSE_NOTIFY_POLL:
                return fuse_notify_poll(fc, size, cs);
@@ -2217,6 +2231,7 @@ static int fuse_dev_fasync(int fd, struct file *file, int on)
 
 const struct file_operations fuse_dev_operations = {
        .owner          = THIS_MODULE,
+       .open           = fuse_dev_open,
        .llseek         = no_llseek,
        .read           = do_sync_read,
        .aio_read       = fuse_dev_read,
index 6e560d5..754fdf8 100644 (file)
@@ -131,13 +131,16 @@ skip:
        hfs_bnode_write(node, entry, data_off + key_len, entry_len);
        hfs_bnode_dump(node);
 
-       if (new_node) {
-               /* update parent key if we inserted a key
-                * at the start of the first node
-                */
-               if (!rec && new_node != node)
-                       hfs_brec_update_parent(fd);
+       /*
+        * update parent key if we inserted a key
+        * at the start of the node and it is not the new node
+        */
+       if (!rec && new_node != node) {
+               hfs_bnode_read_key(node, fd->search_key, data_off + size);
+               hfs_brec_update_parent(fd);
+       }
 
+       if (new_node) {
                hfs_bnode_put(fd->bnode);
                if (!new_node->parent) {
                        hfs_btree_inc_height(tree);
@@ -168,9 +171,6 @@ skip:
                goto again;
        }
 
-       if (!rec)
-               hfs_brec_update_parent(fd);
-
        return 0;
 }
 
@@ -370,6 +370,8 @@ again:
        if (IS_ERR(parent))
                return PTR_ERR(parent);
        __hfs_brec_find(parent, fd, hfs_find_rec_by_key);
+       if (fd->record < 0)
+               return -ENOENT;
        hfs_bnode_dump(parent);
        rec = fd->record;
 
index b684e8a..2bacb99 100644 (file)
@@ -207,6 +207,7 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
                goto out_free;
        }
 
+       of->event = atomic_read(&of->kn->attr.open->event);
        ops = kernfs_ops(of->kn);
        if (ops->read)
                len = ops->read(of, buf, len, *ppos);
index 365c82e..40bc384 100644 (file)
@@ -1388,9 +1388,8 @@ any_leases_conflict(struct inode *inode, struct file_lock *breaker)
 int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 {
        int error = 0;
-       struct file_lock *new_fl;
        struct file_lock_context *ctx = inode->i_flctx;
-       struct file_lock *fl;
+       struct file_lock *new_fl, *fl, *tmp;
        unsigned long break_time;
        int want_write = (mode & O_ACCMODE) != O_RDONLY;
        LIST_HEAD(dispose);
@@ -1420,7 +1419,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
                        break_time++;   /* so that 0 means no break time */
        }
 
-       list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
+       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
                if (!leases_conflict(fl, new_fl))
                        continue;
                if (want_write) {
@@ -1665,7 +1664,8 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
        }
 
        if (my_fl != NULL) {
-               error = lease->fl_lmops->lm_change(my_fl, arg, &dispose);
+               lease = my_fl;
+               error = lease->fl_lmops->lm_change(lease, arg, &dispose);
                if (error)
                        goto out;
                goto out_setup;
@@ -1727,7 +1727,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
                        break;
                }
        }
-       trace_generic_delete_lease(inode, fl);
+       trace_generic_delete_lease(inode, victim);
        if (victim)
                error = fl->fl_lmops->lm_change(victim, F_UNLCK, &dispose);
        spin_unlock(&ctx->flc_lock);
index f9f4845..1987415 100644 (file)
@@ -433,7 +433,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
 
 static bool nfs_client_init_is_complete(const struct nfs_client *clp)
 {
-       return clp->cl_cons_state != NFS_CS_INITING;
+       return clp->cl_cons_state <= NFS_CS_READY;
 }
 
 int nfs_wait_client_init_complete(const struct nfs_client *clp)
index a1f0685..a6ad688 100644 (file)
@@ -181,8 +181,8 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
                        clear_bit(NFS_DELEGATION_NEED_RECLAIM,
                                  &delegation->flags);
                        spin_unlock(&delegation->lock);
-                       put_rpccred(oldcred);
                        rcu_read_unlock();
+                       put_rpccred(oldcred);
                        trace_nfs4_reclaim_delegation(inode, res->delegation_type);
                } else {
                        /* We appear to have raced with a delegation return. */
@@ -370,7 +370,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
                        delegation = NULL;
                        goto out;
                }
-               freeme = nfs_detach_delegation_locked(nfsi, 
+               if (test_and_set_bit(NFS_DELEGATION_RETURNING,
+                                       &old_delegation->flags))
+                       goto out;
+               freeme = nfs_detach_delegation_locked(nfsi,
                                old_delegation, clp);
                if (freeme == NULL)
                        goto out;
@@ -433,6 +436,8 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
 {
        bool ret = false;
 
+       if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
+               goto out;
        if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
                ret = true;
        if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
@@ -444,6 +449,7 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
                        ret = true;
                spin_unlock(&delegation->lock);
        }
+out:
        return ret;
 }
 
@@ -471,14 +477,20 @@ restart:
                                                                super_list) {
                        if (!nfs_delegation_need_return(delegation))
                                continue;
-                       inode = nfs_delegation_grab_inode(delegation);
-                       if (inode == NULL)
+                       if (!nfs_sb_active(server->super))
                                continue;
+                       inode = nfs_delegation_grab_inode(delegation);
+                       if (inode == NULL) {
+                               rcu_read_unlock();
+                               nfs_sb_deactive(server->super);
+                               goto restart;
+                       }
                        delegation = nfs_start_delegation_return_locked(NFS_I(inode));
                        rcu_read_unlock();
 
                        err = nfs_end_delegation_return(inode, delegation, 0);
                        iput(inode);
+                       nfs_sb_deactive(server->super);
                        if (!err)
                                goto restart;
                        set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
@@ -809,19 +821,30 @@ restart:
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
                list_for_each_entry_rcu(delegation, &server->delegations,
                                                                super_list) {
+                       if (test_bit(NFS_DELEGATION_RETURNING,
+                                               &delegation->flags))
+                               continue;
                        if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
                                                &delegation->flags) == 0)
                                continue;
-                       inode = nfs_delegation_grab_inode(delegation);
-                       if (inode == NULL)
+                       if (!nfs_sb_active(server->super))
                                continue;
-                       delegation = nfs_detach_delegation(NFS_I(inode),
-                                       delegation, server);
+                       inode = nfs_delegation_grab_inode(delegation);
+                       if (inode == NULL) {
+                               rcu_read_unlock();
+                               nfs_sb_deactive(server->super);
+                               goto restart;
+                       }
+                       delegation = nfs_start_delegation_return_locked(NFS_I(inode));
                        rcu_read_unlock();
-
-                       if (delegation != NULL)
-                               nfs_free_delegation(delegation);
+                       if (delegation != NULL) {
+                               delegation = nfs_detach_delegation(NFS_I(inode),
+                                       delegation, server);
+                               if (delegation != NULL)
+                                       nfs_free_delegation(delegation);
+                       }
                        iput(inode);
+                       nfs_sb_deactive(server->super);
                        goto restart;
                }
        }
index 9b0c55c..c19e16f 100644 (file)
@@ -408,14 +408,22 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc,
        return 0;
 }
 
+/* Match file and dirent using either filehandle or fileid
+ * Note: caller is responsible for checking the fsid
+ */
 static
 int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
 {
+       struct nfs_inode *nfsi;
+
        if (dentry->d_inode == NULL)
                goto different;
-       if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0)
-               goto different;
-       return 1;
+
+       nfsi = NFS_I(dentry->d_inode);
+       if (entry->fattr->fileid == nfsi->fileid)
+               return 1;
+       if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0)
+               return 1;
 different:
        return 0;
 }
@@ -469,6 +477,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
        struct inode *inode;
        int status;
 
+       if (!(entry->fattr->valid & NFS_ATTR_FATTR_FILEID))
+               return;
+       if (!(entry->fattr->valid & NFS_ATTR_FATTR_FSID))
+               return;
        if (filename.name[0] == '.') {
                if (filename.len == 1)
                        return;
@@ -479,6 +491,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 
        dentry = d_lookup(parent, &filename);
        if (dentry != NULL) {
+               /* Is there a mountpoint here? If so, just exit */
+               if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
+                                       &entry->fattr->fsid))
+                       goto out;
                if (nfs_same_file(dentry, entry)) {
                        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                        status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
index 94712fc..e679d24 100644 (file)
@@ -178,7 +178,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
                iocb->ki_filp,
                iov_iter_count(to), (unsigned long) iocb->ki_pos);
 
-       result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
+       result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping);
        if (!result) {
                result = generic_file_read_iter(iocb, to);
                if (result > 0)
@@ -199,7 +199,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
        dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
                filp, (unsigned long) count, (unsigned long long) *ppos);
 
-       res = nfs_revalidate_mapping(inode, filp->f_mapping);
+       res = nfs_revalidate_mapping_protected(inode, filp->f_mapping);
        if (!res) {
                res = generic_file_splice_read(filp, ppos, pipe, count, flags);
                if (res > 0)
@@ -372,6 +372,10 @@ start:
                                 nfs_wait_bit_killable, TASK_KILLABLE);
        if (ret)
                return ret;
+       /*
+        * Wait for O_DIRECT to complete
+        */
+       nfs_inode_dio_wait(mapping->host);
 
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page)
@@ -619,6 +623,9 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        /* make sure the cache has finished storing the page */
        nfs_fscache_wait_on_page_write(NFS_I(inode), page);
 
+       wait_on_bit_action(&NFS_I(inode)->flags, NFS_INO_INVALIDATING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+
        lock_page(page);
        mapping = page_file_mapping(page);
        if (mapping != inode->i_mapping)
index 83107be..d42dff6 100644 (file)
@@ -556,6 +556,7 @@ EXPORT_SYMBOL_GPL(nfs_setattr);
  * This is a copy of the common vmtruncate, but with the locking
  * corrected to take into account the fact that NFS requires
  * inode->i_size to be updated under the inode->i_lock.
+ * Note: must be called with inode->i_lock held!
  */
 static int nfs_vmtruncate(struct inode * inode, loff_t offset)
 {
@@ -565,14 +566,14 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
        if (err)
                goto out;
 
-       spin_lock(&inode->i_lock);
        i_size_write(inode, offset);
        /* Optimisation */
        if (offset == 0)
                NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
-       spin_unlock(&inode->i_lock);
 
+       spin_unlock(&inode->i_lock);
        truncate_pagecache(inode, offset);
+       spin_lock(&inode->i_lock);
 out:
        return err;
 }
@@ -585,10 +586,15 @@ out:
  * Note: we do this in the *proc.c in order to ensure that
  *       it works for things like exclusive creates too.
  */
-void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
+void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
+               struct nfs_fattr *fattr)
 {
+       /* Barrier: bump the attribute generation count. */
+       nfs_fattr_set_barrier(fattr);
+
+       spin_lock(&inode->i_lock);
+       NFS_I(inode)->attr_gencount = fattr->gencount;
        if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
-               spin_lock(&inode->i_lock);
                if ((attr->ia_valid & ATTR_MODE) != 0) {
                        int mode = attr->ia_mode & S_IALLUGO;
                        mode |= inode->i_mode & ~S_IALLUGO;
@@ -600,12 +606,13 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
                        inode->i_gid = attr->ia_gid;
                nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL);
-               spin_unlock(&inode->i_lock);
        }
        if ((attr->ia_valid & ATTR_SIZE) != 0) {
                nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
                nfs_vmtruncate(inode, attr->ia_size);
        }
+       nfs_update_inode(inode, fattr);
+       spin_unlock(&inode->i_lock);
 }
 EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
 
@@ -1028,6 +1035,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
 
        if (mapping->nrpages != 0) {
                if (S_ISREG(inode->i_mode)) {
+                       unmap_mapping_range(mapping, 0, 0, 0);
                        ret = nfs_sync_mapping(mapping);
                        if (ret < 0)
                                return ret;
@@ -1060,11 +1068,14 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
 }
 
 /**
- * nfs_revalidate_mapping - Revalidate the pagecache
+ * __nfs_revalidate_mapping - Revalidate the pagecache
  * @inode - pointer to host inode
  * @mapping - pointer to mapping
+ * @may_lock - take inode->i_mutex?
  */
-int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+static int __nfs_revalidate_mapping(struct inode *inode,
+               struct address_space *mapping,
+               bool may_lock)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        unsigned long *bitlock = &nfsi->flags;
@@ -1113,7 +1124,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
        nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
        spin_unlock(&inode->i_lock);
        trace_nfs_invalidate_mapping_enter(inode);
-       ret = nfs_invalidate_mapping(inode, mapping);
+       if (may_lock) {
+               mutex_lock(&inode->i_mutex);
+               ret = nfs_invalidate_mapping(inode, mapping);
+               mutex_unlock(&inode->i_mutex);
+       } else
+               ret = nfs_invalidate_mapping(inode, mapping);
        trace_nfs_invalidate_mapping_exit(inode, ret);
 
        clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
@@ -1123,6 +1139,29 @@ out:
        return ret;
 }
 
+/**
+ * nfs_revalidate_mapping - Revalidate the pagecache
+ * @inode - pointer to host inode
+ * @mapping - pointer to mapping
+ */
+int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+{
+       return __nfs_revalidate_mapping(inode, mapping, false);
+}
+
+/**
+ * nfs_revalidate_mapping_protected - Revalidate the pagecache
+ * @inode - pointer to host inode
+ * @mapping - pointer to mapping
+ *
+ * Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex
+ * while invalidating the mapping.
+ */
+int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping)
+{
+       return __nfs_revalidate_mapping(inode, mapping, true);
+}
+
 static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -1231,13 +1270,6 @@ static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fat
        return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
 }
 
-static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
-{
-       if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
-               return 0;
-       return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
-}
-
 static atomic_long_t nfs_attr_generation_counter;
 
 static unsigned long nfs_read_attr_generation_counter(void)
@@ -1249,6 +1281,7 @@ unsigned long nfs_inc_attr_generation_counter(void)
 {
        return atomic_long_inc_return(&nfs_attr_generation_counter);
 }
+EXPORT_SYMBOL_GPL(nfs_inc_attr_generation_counter);
 
 void nfs_fattr_init(struct nfs_fattr *fattr)
 {
@@ -1260,6 +1293,22 @@ void nfs_fattr_init(struct nfs_fattr *fattr)
 }
 EXPORT_SYMBOL_GPL(nfs_fattr_init);
 
+/**
+ * nfs_fattr_set_barrier
+ * @fattr: attributes
+ *
+ * Used to set a barrier after an attribute was updated. This
+ * barrier ensures that older attributes from RPC calls that may
+ * have raced with our update cannot clobber these new values.
+ * Note that you are still responsible for ensuring that other
+ * operations which change the attribute on the server do not
+ * collide.
+ */
+void nfs_fattr_set_barrier(struct nfs_fattr *fattr)
+{
+       fattr->gencount = nfs_inc_attr_generation_counter();
+}
+
 struct nfs_fattr *nfs_alloc_fattr(void)
 {
        struct nfs_fattr *fattr;
@@ -1370,7 +1419,6 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
 
        return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 ||
                nfs_ctime_need_update(inode, fattr) ||
-               nfs_size_need_update(inode, fattr) ||
                ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
 }
 
@@ -1460,6 +1508,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        int status;
 
        spin_lock(&inode->i_lock);
+       nfs_fattr_set_barrier(fattr);
        status = nfs_post_op_update_inode_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
 
@@ -1468,7 +1517,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
 
 /**
- * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache
  * @inode - pointer to inode
  * @fattr - updated attributes
  *
@@ -1478,11 +1527,10 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
  *
  * This function is mainly designed to be used by the ->write_done() functions.
  */
-int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr)
 {
        int status;
 
-       spin_lock(&inode->i_lock);
        /* Don't do a WCC update if these attributes are already stale */
        if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
                        !nfs_inode_attrs_need_update(inode, fattr)) {
@@ -1514,6 +1562,27 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
        }
 out_noforce:
        status = nfs_post_op_update_inode_locked(inode, fattr);
+       return status;
+}
+
+/**
+ * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * @inode - pointer to inode
+ * @fattr - updated attributes
+ *
+ * After an operation that has changed the inode metadata, mark the
+ * attribute cache as being invalid, then try to update it. Fake up
+ * weak cache consistency data, if none exist.
+ *
+ * This function is mainly designed to be used by the ->write_done() functions.
+ */
+int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+{
+       int status;
+
+       spin_lock(&inode->i_lock);
+       nfs_fattr_set_barrier(fattr);
+       status = nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
        return status;
 }
@@ -1715,6 +1784,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
+               /* Set barrier to be more recent than all outstanding updates */
                nfsi->attr_gencount = nfs_inc_attr_generation_counter();
        } else {
                if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
@@ -1722,6 +1792,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                                nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
                        nfsi->attrtimeo_timestamp = now;
                }
+               /* Set the barrier to be more recent than this fattr */
+               if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
+                       nfsi->attr_gencount = fattr->gencount;
        }
        invalid &= ~NFS_INO_INVALID_ATTR;
        /* Don't invalidate the data if we were to blame */
index b802fb3..9e6475b 100644 (file)
@@ -459,6 +459,7 @@ void nfs_mark_request_commit(struct nfs_page *req,
                             struct nfs_commit_info *cinfo,
                             u32 ds_commit_idx);
 int nfs_write_need_commit(struct nfs_pgio_header *);
+void nfs_writeback_update_inode(struct nfs_pgio_header *hdr);
 int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
                            int how, struct nfs_commit_info *cinfo);
 void nfs_retry_commit(struct list_head *page_list,
index 78e557c..1f11d25 100644 (file)
@@ -138,7 +138,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        nfs_fattr_init(fattr);
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
        if (status == 0)
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
        dprintk("NFS reply setattr: %d\n", status);
        return status;
 }
@@ -834,7 +834,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
        if (nfs3_async_handle_jukebox(task, inode))
                return -EAGAIN;
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr);
+               nfs_writeback_update_inode(hdr);
        return 0;
 }
 
index 2a932fd..53852a4 100644 (file)
@@ -1987,6 +1987,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
                        entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
 
+               if (entry->fattr->fileid != entry->ino) {
+                       entry->fattr->mounted_on_fileid = entry->ino;
+                       entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
+               }
+
                /* In fact, a post_op_fh3: */
                p = xdr_inline_decode(xdr, 4);
                if (unlikely(p == NULL))
index 8646af9..86d6214 100644 (file)
@@ -621,6 +621,9 @@ int nfs41_walk_client_list(struct nfs_client *new,
        spin_lock(&nn->nfs_client_lock);
        list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
 
+               if (pos == new)
+                       goto found;
+
                if (pos->rpc_ops != new->rpc_ops)
                        continue;
 
@@ -639,10 +642,6 @@ int nfs41_walk_client_list(struct nfs_client *new,
                        prev = pos;
 
                        status = nfs_wait_client_init_complete(pos);
-                       if (pos->cl_cons_state == NFS_CS_SESSION_INITING) {
-                               nfs4_schedule_lease_recovery(pos);
-                               status = nfs4_wait_clnt_recover(pos);
-                       }
                        spin_lock(&nn->nfs_client_lock);
                        if (status < 0)
                                break;
@@ -668,7 +667,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
                 */
                if (!nfs4_match_client_owner_id(pos, new))
                        continue;
-
+found:
                atomic_inc(&pos->cl_count);
                *result = pos;
                status = 0;
index 88180ac..627f37c 100644 (file)
@@ -901,6 +901,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
        if (!cinfo->atomic || cinfo->before != dir->i_version)
                nfs_force_lookup_revalidate(dir);
        dir->i_version = cinfo->after;
+       nfsi->attr_gencount = nfs_inc_attr_generation_counter();
        nfs_fscache_invalidate(dir);
        spin_unlock(&dir->i_lock);
 }
@@ -1552,6 +1553,9 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod
 
        opendata->o_arg.open_flags = 0;
        opendata->o_arg.fmode = fmode;
+       opendata->o_arg.share_access = nfs4_map_atomic_open_share(
+                       NFS_SB(opendata->dentry->d_sb),
+                       fmode, 0);
        memset(&opendata->o_res, 0, sizeof(opendata->o_res));
        memset(&opendata->c_res, 0, sizeof(opendata->c_res));
        nfs4_init_opendata_res(opendata);
@@ -2413,8 +2417,8 @@ static int _nfs4_do_open(struct inode *dir,
                                opendata->o_res.f_attr, sattr,
                                state, label, olabel);
                if (status == 0) {
-                       nfs_setattr_update_inode(state->inode, sattr);
-                       nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
+                       nfs_setattr_update_inode(state->inode, sattr,
+                                       opendata->o_res.f_attr);
                        nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
                }
        }
@@ -2651,7 +2655,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                case -NFS4ERR_BAD_STATEID:
                case -NFS4ERR_EXPIRED:
                        if (!nfs4_stateid_match(&calldata->arg.stateid,
-                                               &state->stateid)) {
+                                               &state->open_stateid)) {
                                rpc_restart_call_prepare(task);
                                goto out_release;
                        }
@@ -2687,7 +2691,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
        is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
        is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
-       nfs4_stateid_copy(&calldata->arg.stateid, &state->stateid);
+       nfs4_stateid_copy(&calldata->arg.stateid, &state->open_stateid);
        /* Calculate the change in open mode */
        calldata->arg.fmode = 0;
        if (state->n_rdwr == 0) {
@@ -3288,7 +3292,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 
        status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label);
        if (status == 0) {
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
                nfs_setsecurity(inode, fattr, label);
        }
        nfs4_label_free(label);
@@ -4234,7 +4238,7 @@ static int nfs4_write_done_cb(struct rpc_task *task,
        }
        if (task->tk_status >= 0) {
                renew_lease(NFS_SERVER(inode), hdr->timestamp);
-               nfs_post_op_update_inode_force_wcc(inode, &hdr->fattr);
+               nfs_writeback_update_inode(hdr);
        }
        return 0;
 }
@@ -6893,9 +6897,13 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
 
        if (status == 0) {
                clp->cl_clientid = res.clientid;
-               clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
-               if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R))
+               clp->cl_exchange_flags = res.flags;
+               /* Client ID is not confirmed */
+               if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
+                       clear_bit(NFS4_SESSION_ESTABLISHED,
+                                       &clp->cl_session->session_state);
                        clp->cl_seqid = res.seqid;
+               }
 
                kfree(clp->cl_serverowner);
                clp->cl_serverowner = res.server_owner;
@@ -7227,6 +7235,9 @@ static void nfs4_update_session(struct nfs4_session *session,
                struct nfs41_create_session_res *res)
 {
        nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
+       /* Mark client id and session as being confirmed */
+       session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
+       set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state);
        session->flags = res->flags;
        memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
        if (res->flags & SESSION4_BACK_CHAN)
@@ -7322,8 +7333,8 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
        dprintk("--> nfs4_proc_destroy_session\n");
 
        /* session is still being setup */
-       if (session->clp->cl_cons_state != NFS_CS_READY)
-               return status;
+       if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state))
+               return 0;
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        trace_nfs4_destroy_session(session->clp, status);
index fc46c74..e3ea2c5 100644 (file)
@@ -70,6 +70,7 @@ struct nfs4_session {
 
 enum nfs4_session_state {
        NFS4_SESSION_INITING,
+       NFS4_SESSION_ESTABLISHED,
 };
 
 extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
index 5ad908e..f95e3b5 100644 (file)
@@ -346,9 +346,23 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
        status = nfs4_proc_exchange_id(clp, cred);
        if (status != NFS4_OK)
                return status;
-       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
 
-       return nfs41_walk_client_list(clp, result, cred);
+       status = nfs41_walk_client_list(clp, result, cred);
+       if (status < 0)
+               return status;
+       if (clp != *result)
+               return 0;
+
+       /* Purge state if the client id was established in a prior instance */
+       if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R)
+               set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
+       else
+               set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       nfs4_schedule_state_manager(clp);
+       status = nfs_wait_client_init_complete(clp);
+       if (status < 0)
+               nfs_put_client(clp);
+       return status;
 }
 
 #endif /* CONFIG_NFS_V4_1 */
index b09cc23..c63189a 100644 (file)
@@ -139,7 +139,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        nfs_fattr_init(fattr);
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
        if (status == 0)
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
        dprintk("NFS reply setattr: %d\n", status);
        return status;
 }
@@ -609,10 +609,8 @@ static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task,
 
 static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
 {
-       struct inode *inode = hdr->inode;
-
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr);
+               nfs_writeback_update_inode(hdr);
        return 0;
 }
 
index 595d81e..849ed78 100644 (file)
@@ -1377,6 +1377,36 @@ static int nfs_should_remove_suid(const struct inode *inode)
        return 0;
 }
 
+static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
+               struct nfs_fattr *fattr)
+{
+       struct nfs_pgio_args *argp = &hdr->args;
+       struct nfs_pgio_res *resp = &hdr->res;
+
+       if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
+               return;
+       if (argp->offset + resp->count != fattr->size)
+               return;
+       if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode))
+               return;
+       /* Set attribute barrier */
+       nfs_fattr_set_barrier(fattr);
+}
+
+void nfs_writeback_update_inode(struct nfs_pgio_header *hdr)
+{
+       struct nfs_fattr *fattr = hdr->res.fattr;
+       struct inode *inode = hdr->inode;
+
+       if (fattr == NULL)
+               return;
+       spin_lock(&inode->i_lock);
+       nfs_writeback_check_extend(hdr, fattr);
+       nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
+       spin_unlock(&inode->i_lock);
+}
+EXPORT_SYMBOL_GPL(nfs_writeback_update_inode);
+
 /*
  * This function is called when the WRITE call is complete.
  */
index cdbc78c..03d647b 100644 (file)
@@ -137,7 +137,7 @@ nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
        seg->offset = iomap.offset;
        seg->length = iomap.length;
 
-       dprintk("GET: %lld:%lld %d\n", bex->foff, bex->len, bex->es);
+       dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es);
        return 0;
 
 out_error:
index 9da89fd..9aa2796 100644 (file)
@@ -122,19 +122,19 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
 
                p = xdr_decode_hyper(p, &bex.foff);
                if (bex.foff & (block_size - 1)) {
-                       dprintk("%s: unaligned offset %lld\n",
+                       dprintk("%s: unaligned offset 0x%llx\n",
                                __func__, bex.foff);
                        goto fail;
                }
                p = xdr_decode_hyper(p, &bex.len);
                if (bex.len & (block_size - 1)) {
-                       dprintk("%s: unaligned length %lld\n",
+                       dprintk("%s: unaligned length 0x%llx\n",
                                __func__, bex.foff);
                        goto fail;
                }
                p = xdr_decode_hyper(p, &bex.soff);
                if (bex.soff & (block_size - 1)) {
-                       dprintk("%s: unaligned disk offset %lld\n",
+                       dprintk("%s: unaligned disk offset 0x%llx\n",
                                __func__, bex.soff);
                        goto fail;
                }
index 3c1bfa1..6904213 100644 (file)
@@ -118,7 +118,7 @@ void nfsd4_setup_layout_type(struct svc_export *exp)
 {
        struct super_block *sb = exp->ex_path.mnt->mnt_sb;
 
-       if (exp->ex_flags & NFSEXP_NOPNFS)
+       if (!(exp->ex_flags & NFSEXP_PNFS))
                return;
 
        if (sb->s_export_op->get_uuid &&
@@ -440,15 +440,14 @@ nfsd4_return_file_layout(struct nfs4_layout *lp, struct nfsd4_layout_seg *seg,
                        list_move_tail(&lp->lo_perstate, reaplist);
                        return;
                }
-               end = seg->offset;
+               lo->offset = layout_end(seg);
        } else {
                /* retain the whole layout segment on a split. */
                if (layout_end(seg) < end) {
                        dprintk("%s: split not supported\n", __func__);
                        return;
                }
-
-               lo->offset = layout_end(seg);
+               end = seg->offset;
        }
 
        layout_update_len(lo, end);
@@ -513,6 +512,9 @@ nfsd4_return_client_layouts(struct svc_rqst *rqstp,
 
        spin_lock(&clp->cl_lock);
        list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) {
+               if (ls->ls_layout_type != lrp->lr_layout_type)
+                       continue;
+
                if (lrp->lr_return_type == RETURN_FSID &&
                    !fh_fsid_match(&ls->ls_stid.sc_file->fi_fhandle,
                                   &cstate->current_fh.fh_handle))
@@ -587,7 +589,7 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
 
        rpc_ntop((struct sockaddr *)&clp->cl_addr, addr_str, sizeof(addr_str));
 
-       nfsd4_cb_layout_fail(ls);
+       trace_layout_recall_fail(&ls->ls_stid.sc_stateid);
 
        printk(KERN_WARNING
                "nfsd: client %s failed to respond to layout recall. "
index d30bea8..92b9d97 100644 (file)
@@ -1237,8 +1237,8 @@ nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
                nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb, gdp);
 
        gdp->gd_notify_types &= ops->notify_types;
-       exp_put(exp);
 out:
+       exp_put(exp);
        return nfserr;
 }
 
index f6b2a09..8ba1d88 100644 (file)
@@ -1638,7 +1638,7 @@ __destroy_client(struct nfs4_client *clp)
                nfs4_put_stid(&dp->dl_stid);
        }
        while (!list_empty(&clp->cl_revoked)) {
-               dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
+               dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru);
                list_del_init(&dp->dl_recall_lru);
                nfs4_put_stid(&dp->dl_stid);
        }
@@ -3221,7 +3221,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
        } else
                nfs4_free_openowner(&oo->oo_owner);
        spin_unlock(&clp->cl_lock);
-       return oo;
+       return ret;
 }
 
 static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
@@ -5062,7 +5062,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
        } else
                nfs4_free_lockowner(&lo->lo_owner);
        spin_unlock(&clp->cl_lock);
-       return lo;
+       return ret;
 }
 
 static void
index df5e66c..5fb7e78 100644 (file)
@@ -1562,7 +1562,11 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp,
        p = xdr_decode_hyper(p, &lgp->lg_seg.offset);
        p = xdr_decode_hyper(p, &lgp->lg_seg.length);
        p = xdr_decode_hyper(p, &lgp->lg_minlength);
-       nfsd4_decode_stateid(argp, &lgp->lg_sid);
+
+       status = nfsd4_decode_stateid(argp, &lgp->lg_sid);
+       if (status)
+               return status;
+
        READ_BUF(4);
        lgp->lg_maxcount = be32_to_cpup(p++);
 
@@ -1580,7 +1584,11 @@ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp,
        p = xdr_decode_hyper(p, &lcp->lc_seg.offset);
        p = xdr_decode_hyper(p, &lcp->lc_seg.length);
        lcp->lc_reclaim = be32_to_cpup(p++);
-       nfsd4_decode_stateid(argp, &lcp->lc_sid);
+
+       status = nfsd4_decode_stateid(argp, &lcp->lc_sid);
+       if (status)
+               return status;
+
        READ_BUF(4);
        lcp->lc_newoffset = be32_to_cpup(p++);
        if (lcp->lc_newoffset) {
@@ -1628,7 +1636,11 @@ nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp,
                READ_BUF(16);
                p = xdr_decode_hyper(p, &lrp->lr_seg.offset);
                p = xdr_decode_hyper(p, &lrp->lr_seg.length);
-               nfsd4_decode_stateid(argp, &lrp->lr_sid);
+
+               status = nfsd4_decode_stateid(argp, &lrp->lr_sid);
+               if (status)
+                       return status;
+
                READ_BUF(4);
                lrp->lrf_body_len = be32_to_cpup(p++);
                if (lrp->lrf_body_len > 0) {
@@ -4123,7 +4135,7 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
                return nfserr_resource;
        *p++ = cpu_to_be32(lrp->lrs_present);
        if (lrp->lrs_present)
-               nfsd4_encode_stateid(xdr, &lrp->lr_sid);
+               return nfsd4_encode_stateid(xdr, &lrp->lr_sid);
        return nfs_ok;
 }
 #endif /* CONFIG_NFSD_PNFS */
index 83a9694..46ec934 100644 (file)
@@ -165,13 +165,17 @@ int nfsd_reply_cache_init(void)
 {
        unsigned int hashsize;
        unsigned int i;
+       int status = 0;
 
        max_drc_entries = nfsd_cache_size_limit();
        atomic_set(&num_drc_entries, 0);
        hashsize = nfsd_hashsize(max_drc_entries);
        maskbits = ilog2(hashsize);
 
-       register_shrinker(&nfsd_reply_cache_shrinker);
+       status = register_shrinker(&nfsd_reply_cache_shrinker);
+       if (status)
+               return status;
+
        drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep),
                                        0, 0, NULL);
        if (!drc_slab)
index b2e3ff3..ecdbae1 100644 (file)
@@ -31,6 +31,8 @@
 #include "alloc.h"
 #include "dat.h"
 
+static void __nilfs_btree_init(struct nilfs_bmap *bmap);
+
 static struct nilfs_btree_path *nilfs_btree_alloc_path(void)
 {
        struct nilfs_btree_path *path;
@@ -368,6 +370,34 @@ static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
        return ret;
 }
 
+/**
+ * nilfs_btree_root_broken - verify consistency of btree root node
+ * @node: btree root node to be examined
+ * @ino: inode number
+ *
+ * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
+ */
+static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
+                                  unsigned long ino)
+{
+       int level, flags, nchildren;
+       int ret = 0;
+
+       level = nilfs_btree_node_get_level(node);
+       flags = nilfs_btree_node_get_flags(node);
+       nchildren = nilfs_btree_node_get_nchildren(node);
+
+       if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
+                    level > NILFS_BTREE_LEVEL_MAX ||
+                    nchildren < 0 ||
+                    nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
+               pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
+                       ino, level, flags, nchildren);
+               ret = 1;
+       }
+       return ret;
+}
+
 int nilfs_btree_broken_node_block(struct buffer_head *bh)
 {
        int ret;
@@ -1713,7 +1743,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *btree,
 
        /* convert and insert */
        dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL;
-       nilfs_btree_init(btree);
+       __nilfs_btree_init(btree);
        if (nreq != NULL) {
                nilfs_bmap_commit_alloc_ptr(btree, dreq, dat);
                nilfs_bmap_commit_alloc_ptr(btree, nreq, dat);
@@ -2294,12 +2324,23 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = {
        .bop_gather_data        =       NULL,
 };
 
-int nilfs_btree_init(struct nilfs_bmap *bmap)
+static void __nilfs_btree_init(struct nilfs_bmap *bmap)
 {
        bmap->b_ops = &nilfs_btree_ops;
        bmap->b_nchildren_per_block =
                NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(bmap));
-       return 0;
+}
+
+int nilfs_btree_init(struct nilfs_bmap *bmap)
+{
+       int ret = 0;
+
+       __nilfs_btree_init(bmap);
+
+       if (nilfs_btree_root_broken(nilfs_btree_get_root(bmap),
+                                   bmap->b_inode->i_ino))
+               ret = -EIO;
+       return ret;
 }
 
 void nilfs_btree_init_gc(struct nilfs_bmap *bmap)
index 469086b..0c3f303 100644 (file)
@@ -1907,6 +1907,7 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
                                             struct the_nilfs *nilfs)
 {
        struct nilfs_inode_info *ii, *n;
+       int during_mount = !(sci->sc_super->s_flags & MS_ACTIVE);
        int defer_iput = false;
 
        spin_lock(&nilfs->ns_inode_lock);
@@ -1919,10 +1920,10 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
                brelse(ii->i_bh);
                ii->i_bh = NULL;
                list_del_init(&ii->i_dirty);
-               if (!ii->vfs_inode.i_nlink) {
+               if (!ii->vfs_inode.i_nlink || during_mount) {
                        /*
-                        * Defer calling iput() to avoid a deadlock
-                        * over I_SYNC flag for inodes with i_nlink == 0
+                        * Defer calling iput() to avoid deadlocks if
+                        * i_nlink == 0 or mount is not yet finished.
                         */
                        list_add_tail(&ii->i_dirty, &sci->sc_iput_queue);
                        defer_iput = true;
index 9a66ff7..d2f97ec 100644 (file)
@@ -143,7 +143,8 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
            !(marks_mask & FS_ISDIR & ~marks_ignored_mask))
                return false;
 
-       if (event_mask & marks_mask & ~marks_ignored_mask)
+       if (event_mask & FAN_ALL_OUTGOING_EVENTS & marks_mask &
+                                ~marks_ignored_mask)
                return true;
 
        return false;
index 8490c64..460c6c3 100644 (file)
@@ -502,7 +502,7 @@ static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super *osb)
 
 static inline int ocfs2_supports_append_dio(struct ocfs2_super *osb)
 {
-       if (osb->s_feature_ro_compat & OCFS2_FEATURE_RO_COMPAT_APPEND_DIO)
+       if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_APPEND_DIO)
                return 1;
        return 0;
 }
index 20e37a3..db64ce2 100644 (file)
                                         | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \
                                         | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE \
                                         | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG  \
-                                        | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO)
+                                        | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO \
+                                        | OCFS2_FEATURE_INCOMPAT_APPEND_DIO)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP   (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
                                         | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
-                                        | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA \
-                                        | OCFS2_FEATURE_RO_COMPAT_APPEND_DIO)
+                                        | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
 
 /*
  * Heartbeat-only devices are missing journals and other files.  The
  */
 #define OCFS2_FEATURE_INCOMPAT_CLUSTERINFO     0x4000
 
+/*
+ * Append Direct IO support
+ */
+#define OCFS2_FEATURE_INCOMPAT_APPEND_DIO      0x8000
+
 /*
  * backup superblock flag is used to indicate that this volume
  * has backup superblocks.
 #define OCFS2_FEATURE_RO_COMPAT_USRQUOTA       0x0002
 #define OCFS2_FEATURE_RO_COMPAT_GRPQUOTA       0x0004
 
-/*
- * Append Direct IO support
- */
-#define OCFS2_FEATURE_RO_COMPAT_APPEND_DIO     0x0008
 
 /* The byte offset of the first backup block will be 1G.
  * The following will be 4G, 16G, 64G, 256G and 1T.
index b90952f..5f0d199 100644 (file)
@@ -529,8 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data)
 {
        struct ovl_fs *ufs = sb->s_fs_info;
 
-       if (!(*flags & MS_RDONLY) &&
-           (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)))
+       if (!(*flags & MS_RDONLY) && !ufs->upper_mnt)
                return -EROFS;
 
        return 0;
@@ -615,9 +614,19 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
                        break;
 
                default:
+                       pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p);
                        return -EINVAL;
                }
        }
+
+       /* Workdir is useless in non-upper mount */
+       if (!config->upperdir && config->workdir) {
+               pr_info("overlayfs: option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
+                       config->workdir);
+               kfree(config->workdir);
+               config->workdir = NULL;
+       }
+
        return 0;
 }
 
@@ -837,7 +846,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_stack_depth = 0;
        if (ufs->config.upperdir) {
-               /* FIXME: workdir is not needed for a R/O mount */
                if (!ufs->config.workdir) {
                        pr_err("overlayfs: missing 'workdir'\n");
                        goto out_free_config;
@@ -847,6 +855,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                if (err)
                        goto out_free_config;
 
+               /* Upper fs should not be r/o */
+               if (upperpath.mnt->mnt_sb->s_flags & MS_RDONLY) {
+                       pr_err("overlayfs: upper fs is r/o, try multi-lower layers mount\n");
+                       err = -EINVAL;
+                       goto out_put_upperpath;
+               }
+
                err = ovl_mount_dir(ufs->config.workdir, &workpath);
                if (err)
                        goto out_put_upperpath;
@@ -869,8 +884,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        err = -EINVAL;
        stacklen = ovl_split_lowerdirs(lowertmp);
-       if (stacklen > OVL_MAX_STACK)
+       if (stacklen > OVL_MAX_STACK) {
+               pr_err("overlayfs: too many lower directries, limit is %d\n",
+                      OVL_MAX_STACK);
                goto out_free_lowertmp;
+       } else if (!ufs->config.upperdir && stacklen == 1) {
+               pr_err("overlayfs: at least 2 lowerdir are needed while upperdir nonexistent\n");
+               goto out_free_lowertmp;
+       }
 
        stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL);
        if (!stack)
@@ -932,8 +953,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                ufs->numlower++;
        }
 
-       /* If the upper fs is r/o or nonexistent, we mark overlayfs r/o too */
-       if (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY))
+       /* If the upper fs is nonexistent, we mark overlayfs r/o too */
+       if (!ufs->upper_mnt)
                sb->s_flags |= MS_RDONLY;
 
        sb->s_d_op = &ovl_dentry_operations;
index 956b75d..6dee68d 100644 (file)
@@ -1325,6 +1325,9 @@ out:
 
 static int pagemap_open(struct inode *inode, struct file *file)
 {
+       /* do not disclose physical addresses: attack vector */
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
        pr_warn_once("Bits 55-60 of /proc/PID/pagemap entries are about "
                        "to stop being page-shift some time soon. See the "
                        "linux/Documentation/vm/pagemap.txt for details.\n");
index ce615d1..a2e1cb8 100644 (file)
@@ -397,7 +397,8 @@ STATIC int                          /* error (positive) */
 xfs_zero_last_block(
        struct xfs_inode        *ip,
        xfs_fsize_t             offset,
-       xfs_fsize_t             isize)
+       xfs_fsize_t             isize,
+       bool                    *did_zeroing)
 {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_fileoff_t           last_fsb = XFS_B_TO_FSBT(mp, isize);
@@ -425,6 +426,7 @@ xfs_zero_last_block(
        zero_len = mp->m_sb.sb_blocksize - zero_offset;
        if (isize + zero_len > offset)
                zero_len = offset - isize;
+       *did_zeroing = true;
        return xfs_iozero(ip, isize, zero_len);
 }
 
@@ -443,7 +445,8 @@ int                                 /* error (positive) */
 xfs_zero_eof(
        struct xfs_inode        *ip,
        xfs_off_t               offset,         /* starting I/O offset */
-       xfs_fsize_t             isize)          /* current inode size */
+       xfs_fsize_t             isize,          /* current inode size */
+       bool                    *did_zeroing)
 {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_fileoff_t           start_zero_fsb;
@@ -465,7 +468,7 @@ xfs_zero_eof(
         * We only zero a part of that block so it is handled specially.
         */
        if (XFS_B_FSB_OFFSET(mp, isize) != 0) {
-               error = xfs_zero_last_block(ip, offset, isize);
+               error = xfs_zero_last_block(ip, offset, isize, did_zeroing);
                if (error)
                        return error;
        }
@@ -525,6 +528,7 @@ xfs_zero_eof(
                if (error)
                        return error;
 
+               *did_zeroing = true;
                start_zero_fsb = imap.br_startoff + imap.br_blockcount;
                ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
        }
@@ -567,13 +571,15 @@ restart:
         * having to redo all checks before.
         */
        if (*pos > i_size_read(inode)) {
+               bool    zero = false;
+
                if (*iolock == XFS_IOLOCK_SHARED) {
                        xfs_rw_iunlock(ip, *iolock);
                        *iolock = XFS_IOLOCK_EXCL;
                        xfs_rw_ilock(ip, *iolock);
                        goto restart;
                }
-               error = xfs_zero_eof(ip, *pos, i_size_read(inode));
+               error = xfs_zero_eof(ip, *pos, i_size_read(inode), &zero);
                if (error)
                        return error;
        }
index daafa1f..6163767 100644 (file)
@@ -2867,6 +2867,10 @@ xfs_rename(
         * Handle RENAME_EXCHANGE flags
         */
        if (flags & RENAME_EXCHANGE) {
+               if (target_ip == NULL) {
+                       error = -EINVAL;
+                       goto error_return;
+               }
                error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
                                         target_dp, target_name, target_ip,
                                         &free_list, &first_block, spaceres);
index 86cd6b3..a1cd55f 100644 (file)
@@ -384,10 +384,11 @@ enum xfs_prealloc_flags {
        XFS_PREALLOC_INVISIBLE  = (1 << 4),
 };
 
-int            xfs_update_prealloc_flags(struct xfs_inode *,
-                       enum xfs_prealloc_flags);
-int            xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
-int            xfs_iozero(struct xfs_inode *, loff_t, size_t);
+int    xfs_update_prealloc_flags(struct xfs_inode *ip,
+                                 enum xfs_prealloc_flags flags);
+int    xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
+                    xfs_fsize_t isize, bool *did_zeroing);
+int    xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);
 
 
 #define IHOLD(ip) \
index d919ad7..e53a903 100644 (file)
@@ -751,6 +751,7 @@ xfs_setattr_size(
        int                     error;
        uint                    lock_flags = 0;
        uint                    commit_flags = 0;
+       bool                    did_zeroing = false;
 
        trace_xfs_setattr(ip);
 
@@ -794,20 +795,16 @@ xfs_setattr_size(
                return error;
 
        /*
-        * Now we can make the changes.  Before we join the inode to the
-        * transaction, take care of the part of the truncation that must be
-        * done without the inode lock.  This needs to be done before joining
-        * the inode to the transaction, because the inode cannot be unlocked
-        * once it is a part of the transaction.
+        * File data changes must be complete before we start the transaction to
+        * modify the inode.  This needs to be done before joining the inode to
+        * the transaction because the inode cannot be unlocked once it is a
+        * part of the transaction.
+        *
+        * Start with zeroing any data block beyond EOF that we may expose on
+        * file extension.
         */
        if (newsize > oldsize) {
-               /*
-                * Do the first part of growing a file: zero any data in the
-                * last block that is beyond the old EOF.  We need to do this
-                * before the inode is joined to the transaction to modify
-                * i_size.
-                */
-               error = xfs_zero_eof(ip, newsize, oldsize);
+               error = xfs_zero_eof(ip, newsize, oldsize, &did_zeroing);
                if (error)
                        return error;
        }
@@ -817,23 +814,18 @@ xfs_setattr_size(
         * any previous writes that are beyond the on disk EOF and the new
         * EOF that have not been written out need to be written here.  If we
         * do not write the data out, we expose ourselves to the null files
-        * problem.
-        *
-        * Only flush from the on disk size to the smaller of the in memory
-        * file size or the new size as that's the range we really care about
-        * here and prevents waiting for other data not within the range we
-        * care about here.
+        * problem. Note that this includes any block zeroing we did above;
+        * otherwise those blocks may not be zeroed after a crash.
         */
-       if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) {
+       if (newsize > ip->i_d.di_size &&
+           (oldsize != ip->i_d.di_size || did_zeroing)) {
                error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
                                                      ip->i_d.di_size, newsize);
                if (error)
                        return error;
        }
 
-       /*
-        * Wait for all direct I/O to complete.
-        */
+       /* Now wait for all direct I/O to complete. */
        inode_dio_wait(inode);
 
        /*
index 4b33ef1..365dd57 100644 (file)
@@ -300,8 +300,10 @@ xfs_fs_commit_blocks(
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
        error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
-       if (error)
+       if (error) {
+               xfs_trans_cancel(tp, 0);
                goto out_drop_iolock;
+       }
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
index 53cc2aa..fbbb9e6 100644 (file)
@@ -836,6 +836,11 @@ xfs_qm_reset_dqcounts(
                 */
                xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR,
                            "xfs_quotacheck");
+               /*
+                * Reset type in case we are reusing group quota file for
+                * project quotas or vice versa
+                */
+               ddq->d_flags = type;
                ddq->d_bcount = 0;
                ddq->d_icount = 0;
                ddq->d_rtbcount = 0;
index a24addf..0de6290 100644 (file)
@@ -68,8 +68,8 @@ struct drm_mm_node {
        unsigned scanned_preceeds_hole : 1;
        unsigned allocated : 1;
        unsigned long color;
-       unsigned long start;
-       unsigned long size;
+       u64 start;
+       u64 size;
        struct drm_mm *mm;
 };
 
@@ -82,16 +82,16 @@ struct drm_mm {
        unsigned int scan_check_range : 1;
        unsigned scan_alignment;
        unsigned long scan_color;
-       unsigned long scan_size;
-       unsigned long scan_hit_start;
-       unsigned long scan_hit_end;
+       u64 scan_size;
+       u64 scan_hit_start;
+       u64 scan_hit_end;
        unsigned scanned_blocks;
-       unsigned long scan_start;
-       unsigned long scan_end;
+       u64 scan_start;
+       u64 scan_end;
        struct drm_mm_node *prev_scanned_node;
 
        void (*color_adjust)(struct drm_mm_node *node, unsigned long color,
-                            unsigned long *start, unsigned long *end);
+                            u64 *start, u64 *end);
 };
 
 /**
@@ -124,7 +124,7 @@ static inline bool drm_mm_initialized(struct drm_mm *mm)
        return mm->hole_stack.next;
 }
 
-static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
+static inline u64 __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
        return hole_node->start + hole_node->size;
 }
@@ -140,13 +140,13 @@ static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_no
  * Returns:
  * Start of the subsequent hole.
  */
-static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
+static inline u64 drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
        BUG_ON(!hole_node->hole_follows);
        return __drm_mm_hole_node_start(hole_node);
 }
 
-static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
+static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 {
        return list_entry(hole_node->node_list.next,
                          struct drm_mm_node, node_list)->start;
@@ -163,7 +163,7 @@ static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node
  * Returns:
  * End of the subsequent hole.
  */
-static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
+static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 {
        return __drm_mm_hole_node_end(hole_node);
 }
@@ -222,7 +222,7 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);
 
 int drm_mm_insert_node_generic(struct drm_mm *mm,
                               struct drm_mm_node *node,
-                              unsigned long size,
+                              u64 size,
                               unsigned alignment,
                               unsigned long color,
                               enum drm_mm_search_flags sflags,
@@ -245,7 +245,7 @@ int drm_mm_insert_node_generic(struct drm_mm *mm,
  */
 static inline int drm_mm_insert_node(struct drm_mm *mm,
                                     struct drm_mm_node *node,
-                                    unsigned long size,
+                                    u64 size,
                                     unsigned alignment,
                                     enum drm_mm_search_flags flags)
 {
@@ -255,11 +255,11 @@ static inline int drm_mm_insert_node(struct drm_mm *mm,
 
 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
                                        struct drm_mm_node *node,
-                                       unsigned long size,
+                                       u64 size,
                                        unsigned alignment,
                                        unsigned long color,
-                                       unsigned long start,
-                                       unsigned long end,
+                                       u64 start,
+                                       u64 end,
                                        enum drm_mm_search_flags sflags,
                                        enum drm_mm_allocator_flags aflags);
 /**
@@ -282,10 +282,10 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
  */
 static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
                                              struct drm_mm_node *node,
-                                             unsigned long size,
+                                             u64 size,
                                              unsigned alignment,
-                                             unsigned long start,
-                                             unsigned long end,
+                                             u64 start,
+                                             u64 end,
                                              enum drm_mm_search_flags flags)
 {
        return drm_mm_insert_node_in_range_generic(mm, node, size, alignment,
@@ -296,21 +296,21 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
 void drm_mm_remove_node(struct drm_mm_node *node);
 void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
 void drm_mm_init(struct drm_mm *mm,
-                unsigned long start,
-                unsigned long size);
+                u64 start,
+                u64 size);
 void drm_mm_takedown(struct drm_mm *mm);
 bool drm_mm_clean(struct drm_mm *mm);
 
 void drm_mm_init_scan(struct drm_mm *mm,
-                     unsigned long size,
+                     u64 size,
                      unsigned alignment,
                      unsigned long color);
 void drm_mm_init_scan_with_range(struct drm_mm *mm,
-                                unsigned long size,
+                                u64 size,
                                 unsigned alignment,
                                 unsigned long color,
-                                unsigned long start,
-                                unsigned long end);
+                                u64 start,
+                                u64 end);
 bool drm_mm_scan_add_block(struct drm_mm_node *node);
 bool drm_mm_scan_remove_block(struct drm_mm_node *node);
 
index 180ad0e..d016dc5 100644 (file)
        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, 0x1602, info), /* Halo */ \
        _INTEL_BDW_M(gt, 0x1606, info), /* ULT */ \
-       _INTEL_BDW_M(gt, 0x160B, info), /* Iris */ \
+       _INTEL_BDW_M(gt, 0x160B, info), /* ULT */ \
        _INTEL_BDW_M(gt, 0x160E, info) /* ULX */
 
 #define _INTEL_BDW_D_IDS(gt, info) \
index 0ccf7f2..c768ddf 100644 (file)
@@ -249,7 +249,7 @@ struct ttm_buffer_object {
         * either of these locks held.
         */
 
-       unsigned long offset;
+       uint64_t offset; /* GPU address space is independent of CPU word size */
        uint32_t cur_placement;
 
        struct sg_table *sg;
index 142d752..813042c 100644 (file)
@@ -277,7 +277,7 @@ struct ttm_mem_type_manager {
        bool has_type;
        bool use_type;
        uint32_t flags;
-       unsigned long gpu_offset;
+       uint64_t gpu_offset; /* GPU address space is independent of CPU word size */
        uint64_t size;
        uint32_t available_caching;
        uint32_t default_caching;
index 2fbc804..226f772 100644 (file)
@@ -13,7 +13,8 @@
 
 #define PULL_DISABLE           (1 << 3)
 #define INPUT_EN               (1 << 5)
-#define SLEWCTRL_FAST          (1 << 6)
+#define SLEWCTRL_SLOW          (1 << 6)
+#define SLEWCTRL_FAST          0
 
 /* update macro depending on INPUT_EN and PULL_ENA */
 #undef PIN_OUTPUT
index 9c2e4f8..5f4d018 100644 (file)
@@ -18,7 +18,8 @@
 #define PULL_DISABLE           (1 << 16)
 #define PULL_UP                        (1 << 17)
 #define INPUT_EN               (1 << 18)
-#define SLEWCTRL_FAST          (1 << 19)
+#define SLEWCTRL_SLOW          (1 << 19)
+#define SLEWCTRL_FAST          0
 #define DS0_PULL_UP_DOWN_EN    (1 << 27)
 
 #define PIN_OUTPUT             (PULL_DISABLE)
index 7c55dd5..66203b2 100644 (file)
@@ -114,6 +114,7 @@ struct vgic_ops {
        void    (*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
        u64     (*get_elrsr)(const struct kvm_vcpu *vcpu);
        u64     (*get_eisr)(const struct kvm_vcpu *vcpu);
+       void    (*clear_eisr)(struct kvm_vcpu *vcpu);
        u32     (*get_interrupt_status)(const struct kvm_vcpu *vcpu);
        void    (*enable_underflow)(struct kvm_vcpu *vcpu);
        void    (*disable_underflow)(struct kvm_vcpu *vcpu);
index 8381bbf..68c16a6 100644 (file)
@@ -125,6 +125,19 @@ int clk_set_phase(struct clk *clk, int degrees);
  */
 int clk_get_phase(struct clk *clk);
 
+/**
+ * clk_is_match - check if two clk's point to the same hardware clock
+ * @p: clk compared against q
+ * @q: clk compared against p
+ *
+ * Returns true if the two struct clk pointers both point to the same hardware
+ * clock node. Put differently, returns true if struct clk *p and struct clk *q
+ * share the same struct clk_core object.
+ *
+ * Returns false otherwise. Note that two NULL clks are treated as matching.
+ */
+bool clk_is_match(const struct clk *p, const struct clk *q);
+
 #else
 
 static inline long clk_get_accuracy(struct clk *clk)
@@ -142,6 +155,11 @@ static inline long clk_get_phase(struct clk *clk)
        return -ENOTSUPP;
 }
 
+static inline bool clk_is_match(const struct clk *p, const struct clk *q)
+{
+       return p == q;
+}
+
 #endif
 
 /**
index f551a92..306178d 100644 (file)
@@ -126,6 +126,8 @@ struct cpuidle_driver {
 
 #ifdef CONFIG_CPU_IDLE
 extern void disable_cpuidle(void);
+extern bool cpuidle_not_available(struct cpuidle_driver *drv,
+                                 struct cpuidle_device *dev);
 
 extern int cpuidle_select(struct cpuidle_driver *drv,
                          struct cpuidle_device *dev);
@@ -150,11 +152,17 @@ extern void cpuidle_resume(void);
 extern int cpuidle_enable_device(struct cpuidle_device *dev);
 extern void cpuidle_disable_device(struct cpuidle_device *dev);
 extern int cpuidle_play_dead(void);
-extern void cpuidle_enter_freeze(void);
+extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                                     struct cpuidle_device *dev);
+extern int cpuidle_enter_freeze(struct cpuidle_driver *drv,
+                               struct cpuidle_device *dev);
 
 extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
 #else
 static inline void disable_cpuidle(void) { }
+static inline bool cpuidle_not_available(struct cpuidle_driver *drv,
+                                        struct cpuidle_device *dev)
+{return true; }
 static inline int cpuidle_select(struct cpuidle_driver *drv,
                                 struct cpuidle_device *dev)
 {return -ENODEV; }
@@ -183,7 +191,12 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev)
 {return -ENODEV; }
 static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
 static inline int cpuidle_play_dead(void) {return -ENODEV; }
-static inline void cpuidle_enter_freeze(void) { }
+static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                                            struct cpuidle_device *dev)
+{return -ENODEV; }
+static inline int cpuidle_enter_freeze(struct cpuidle_driver *drv,
+                                      struct cpuidle_device *dev)
+{return -ENODEV; }
 static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
        struct cpuidle_device *dev) {return NULL; }
 #endif
index 2646aed..fd23978 100644 (file)
@@ -375,6 +375,7 @@ int dm_create(int minor, struct mapped_device **md);
  */
 struct mapped_device *dm_get_md(dev_t dev);
 void dm_get(struct mapped_device *md);
+int dm_hold(struct mapped_device *md);
 void dm_put(struct mapped_device *md);
 
 /*
index b4d71b5..f4131e8 100644 (file)
@@ -604,6 +604,7 @@ struct inode {
        struct mutex            i_mutex;
 
        unsigned long           dirtied_when;   /* jiffies of first dirtying */
+       unsigned long           dirtied_time_when;
 
        struct hlist_node       i_hash;
        struct list_head        i_wb_list;      /* backing dev IO list */
index 51f7cca..4173a8f 100644 (file)
@@ -33,6 +33,8 @@
  * @units:             Measurment unit for this attribute.
  * @unit_expo:         Exponent used in the data.
  * @size:              Size in bytes for data size.
+ * @logical_minimum:   Logical minimum value for this attribute.
+ * @logical_maximum:   Logical maximum value for this attribute.
  */
 struct hid_sensor_hub_attribute_info {
        u32 usage_id;
@@ -146,6 +148,7 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
 
 /**
 * sensor_hub_input_attr_get_raw_value() - Synchronous read request
+* @hsdev:      Hub device instance.
 * @usage_id:   Attribute usage id of parent physical device as per spec
 * @attr_usage_id:      Attribute usage id as per spec
 * @report_id:  Report id to look for
@@ -160,6 +163,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
                        u32 attr_usage_id, u32 report_id);
 /**
 * sensor_hub_set_feature() - Feature set request
+* @hsdev:      Hub device instance.
 * @report_id:  Report id to look for
 * @field_index:        Field index inside a report
 * @value:      Value to set
@@ -172,6 +176,7 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
 
 /**
 * sensor_hub_get_feature() - Feature get request
+* @hsdev:      Hub device instance.
 * @report_id:  Report id to look for
 * @field_index:        Field index inside a report
 * @value:      Place holder for return value
index d9b05b5..2e88580 100644 (file)
  * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
  *                Used by threaded interrupts which need to keep the
  *                irq line disabled until the threaded handler has been run.
- * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
+ * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend.  Does not guarantee
+ *                   that this interrupt will wake the system from a suspended
+ *                   state.  See Documentation/power/suspend-and-interrupts.txt
  * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
  * IRQF_NO_THREAD - Interrupt cannot be threaded
  * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
  *                resume time.
+ * IRQF_COND_SUSPEND - If the IRQ is shared with a NO_SUSPEND user, execute this
+ *                interrupt handler after suspending interrupts. For system
+ *                wakeup devices users need to implement wakeup detection in
+ *                their interrupt handlers.
  */
 #define IRQF_DISABLED          0x00000020
 #define IRQF_SHARED            0x00000080
@@ -70,6 +76,7 @@
 #define IRQF_FORCE_RESUME      0x00008000
 #define IRQF_NO_THREAD         0x00010000
 #define IRQF_EARLY_RESUME      0x00020000
+#define IRQF_COND_SUSPEND      0x00040000
 
 #define IRQF_TIMER             (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
 
index 800544b..ffbc034 100644 (file)
 #define GICR_PROPBASER_WaWb            (5U << 7)
 #define GICR_PROPBASER_RaWaWt          (6U << 7)
 #define GICR_PROPBASER_RaWaWb          (7U << 7)
+#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
 #define GICR_PROPBASER_IDBITS_MASK     (0x1f)
 
+#define GICR_PENDBASER_NonShareable    (0U << 10)
+#define GICR_PENDBASER_InnerShareable  (1U << 10)
+#define GICR_PENDBASER_OuterShareable  (2U << 10)
+#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10)
+#define GICR_PENDBASER_nCnB            (0U << 7)
+#define GICR_PENDBASER_nC              (1U << 7)
+#define GICR_PENDBASER_RaWt            (2U << 7)
+#define GICR_PENDBASER_RaWb            (3U << 7)
+#define GICR_PENDBASER_WaWt            (4U << 7)
+#define GICR_PENDBASER_WaWb            (5U << 7)
+#define GICR_PENDBASER_RaWaWt          (6U << 7)
+#define GICR_PENDBASER_RaWaWb          (7U << 7)
+#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
+
 /*
  * Re-Distributor registers, offsets from SGI_base
  */
 
 #define GITS_TRANSLATER                        0x10040
 
+#define GITS_CTLR_ENABLE               (1U << 0)
+#define GITS_CTLR_QUIESCENT            (1U << 31)
+
+#define GITS_TYPER_DEVBITS_SHIFT       13
+#define GITS_TYPER_DEVBITS(r)          ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
 #define GITS_TYPER_PTA                 (1UL << 19)
 
 #define GITS_CBASER_VALID              (1UL << 63)
 #define GITS_CBASER_WaWb               (5UL << 59)
 #define GITS_CBASER_RaWaWt             (6UL << 59)
 #define GITS_CBASER_RaWaWb             (7UL << 59)
+#define GITS_CBASER_CACHEABILITY_MASK  (7UL << 59)
 #define GITS_CBASER_NonShareable       (0UL << 10)
 #define GITS_CBASER_InnerShareable     (1UL << 10)
 #define GITS_CBASER_OuterShareable     (2UL << 10)
 #define GITS_BASER_WaWb                        (5UL << 59)
 #define GITS_BASER_RaWaWt              (6UL << 59)
 #define GITS_BASER_RaWaWb              (7UL << 59)
+#define GITS_BASER_CACHEABILITY_MASK   (7UL << 59)
 #define GITS_BASER_TYPE_SHIFT          (56)
 #define GITS_BASER_TYPE(r)             (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
 #define GITS_BASER_ENTRY_SIZE_SHIFT    (48)
index faf433a..dd1109f 100644 (file)
@@ -78,6 +78,7 @@ struct irq_desc {
 #ifdef CONFIG_PM_SLEEP
        unsigned int            nr_actions;
        unsigned int            no_suspend_depth;
+       unsigned int            cond_suspend_depth;
        unsigned int            force_resume_depth;
 #endif
 #ifdef CONFIG_PROC_FS
index 72ba725..5bb0744 100644 (file)
@@ -5,6 +5,7 @@
 
 struct kmem_cache;
 struct page;
+struct vm_struct;
 
 #ifdef CONFIG_KASAN
 
@@ -49,15 +50,11 @@ void kasan_krealloc(const void *object, size_t new_size);
 void kasan_slab_alloc(struct kmem_cache *s, void *object);
 void kasan_slab_free(struct kmem_cache *s, void *object);
 
-#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
-
 int kasan_module_alloc(void *addr, size_t size);
-void kasan_module_free(void *addr);
+void kasan_free_shadow(const struct vm_struct *vm);
 
 #else /* CONFIG_KASAN */
 
-#define MODULE_ALIGN 1
-
 static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
 
 static inline void kasan_enable_current(void) {}
@@ -82,7 +79,7 @@ static inline void kasan_slab_alloc(struct kmem_cache *s, void *object) {}
 static inline void kasan_slab_free(struct kmem_cache *s, void *object) {}
 
 static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
-static inline void kasan_module_free(void *addr) {}
+static inline void kasan_free_shadow(const struct vm_struct *vm) {}
 
 #endif /* CONFIG_KASAN */
 
index 7bf01d7..1ce79a7 100644 (file)
@@ -4,5 +4,6 @@
 #include <linux/compiler.h>
 
 unsigned long lcm(unsigned long a, unsigned long b) __attribute_const__;
+unsigned long lcm_not_zero(unsigned long a, unsigned long b) __attribute_const__;
 
 #endif /* _LCM_H */
index fc03efa..6b08cc1 100644 (file)
@@ -232,6 +232,7 @@ enum {
                                              * led */
        ATA_FLAG_NO_DIPM        = (1 << 23), /* host not happy with DIPM */
        ATA_FLAG_LOWTAG         = (1 << 24), /* host wants lowest available tag */
+       ATA_FLAG_SAS_HOST       = (1 << 25), /* SAS host */
 
        /* bits 24:31 of ap->flags are reserved for LLD specific flags */
 
index fb0390a..ee7b1ce 100644 (file)
@@ -2999,6 +2999,9 @@ enum usb_irq_events {
 #define PALMAS_GPADC_TRIM15                                    0x0E
 #define PALMAS_GPADC_TRIM16                                    0x0F
 
+/* TPS659038 regen2_ctrl offset iss different from palmas */
+#define TPS659038_REGEN2_CTRL                                  0x12
+
 /* TPS65917 Interrupt registers */
 
 /* Registers for function INTERRUPT */
index 2bbc62a..551f854 100644 (file)
@@ -427,7 +427,7 @@ struct mlx4_wqe_inline_seg {
 
 enum mlx4_update_qp_attr {
        MLX4_UPDATE_QP_SMAC             = 1 << 0,
-       MLX4_UPDATE_QP_VSD              = 1 << 2,
+       MLX4_UPDATE_QP_VSD              = 1 << 1,
        MLX4_UPDATE_QP_SUPPORTED_ATTRS  = (1 << 2) - 1
 };
 
index 42999fe..b03485b 100644 (file)
@@ -344,6 +344,10 @@ struct module {
        unsigned long *ftrace_callsites;
 #endif
 
+#ifdef CONFIG_LIVEPATCH
+       bool klp_alive;
+#endif
+
 #ifdef CONFIG_MODULE_UNLOAD
        /* What modules depend on me? */
        struct list_head source_list;
index f755626..4d0cb9b 100644 (file)
@@ -84,4 +84,12 @@ void module_arch_cleanup(struct module *mod);
 
 /* Any cleanup before freeing mod->module_init */
 void module_arch_freeing_init(struct module *mod);
+
+#ifdef CONFIG_KASAN
+#include <linux/kasan.h>
+#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
+#else
+#define MODULE_ALIGN PAGE_SIZE
+#endif
+
 #endif
index 5897b4e..2787388 100644 (file)
@@ -965,9 +965,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *     Used to add FDB entries to dump requests. Implementers should add
  *     entries to skb and update idx with the number of entries.
  *
- * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh)
+ * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh,
+ *                          u16 flags)
  * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
  *                          struct net_device *dev, u32 filter_mask)
+ * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
+ *                          u16 flags);
  *
  * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
  *     Called to change device carrier. Soft-devices (like dummy, team, etc)
@@ -2182,6 +2185,12 @@ void netdev_freemem(struct net_device *dev);
 void synchronize_net(void);
 int init_dummy_netdev(struct net_device *dev);
 
+DECLARE_PER_CPU(int, xmit_recursion);
+static inline int dev_recursion_level(void)
+{
+       return this_cpu_read(xmit_recursion);
+}
+
 struct net_device *dev_get_by_index(struct net *net, int ifindex);
 struct net_device *__dev_get_by_index(struct net *net, int ifindex);
 struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
@@ -2342,6 +2351,7 @@ struct gro_remcsum {
 
 static inline void skb_gro_remcsum_init(struct gro_remcsum *grc)
 {
+       grc->offset = 0;
        grc->delta = 0;
 }
 
index 2f77e0c..b01ccf3 100644 (file)
@@ -343,6 +343,7 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
+extern int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
 extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
@@ -355,8 +356,9 @@ extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
 extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+extern int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping);
 extern int nfs_setattr(struct dentry *, struct iattr *);
-extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
+extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *);
 extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
                                struct nfs4_label *label);
 extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
@@ -369,6 +371,7 @@ extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ct
 extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);
 extern u64 nfs_compat_user_ino64(u64 fileid);
 extern void nfs_fattr_init(struct nfs_fattr *fattr);
+extern void nfs_fattr_set_barrier(struct nfs_fattr *fattr);
 extern unsigned long nfs_inc_attr_generation_counter(void);
 
 extern struct nfs_fattr *nfs_alloc_fattr(void);
index 8a860f0..611a691 100644 (file)
@@ -84,7 +84,7 @@ static inline int of_platform_populate(struct device_node *root,
 static inline void of_platform_depopulate(struct device *parent) { }
 #endif
 
-#ifdef CONFIG_OF_DYNAMIC
+#if defined(CONFIG_OF_DYNAMIC) && defined(CONFIG_OF_ADDRESS)
 extern void of_platform_register_reconfig_notifier(void);
 #else
 static inline void of_platform_register_reconfig_notifier(void) { }
index 72c0415..18eccef 100644 (file)
@@ -82,7 +82,7 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio)
 
 static inline struct pinctrl * __must_check pinctrl_get(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline void pinctrl_put(struct pinctrl *p)
@@ -93,7 +93,7 @@ static inline struct pinctrl_state * __must_check pinctrl_lookup_state(
                                                        struct pinctrl *p,
                                                        const char *name)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline int pinctrl_select_state(struct pinctrl *p,
@@ -104,7 +104,7 @@ static inline int pinctrl_select_state(struct pinctrl *p,
 
 static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline void devm_pinctrl_put(struct pinctrl *p)
index d4ad5b5..045f709 100644 (file)
@@ -316,7 +316,7 @@ struct regulator_desc {
  * @driver_data: private regulator data
  * @of_node: OpenFirmware node to parse for device tree bindings (may be
  *           NULL).
- * @regmap: regmap to use for core regmap helpers if dev_get_regulator() is
+ * @regmap: regmap to use for core regmap helpers if dev_get_regmap() is
  *          insufficient.
  * @ena_gpio_initialized: GPIO controlling regulator enable was properly
  *                        initialized, meaning that >= 0 is a valid gpio
index 5885127..d438eeb 100644 (file)
@@ -54,10 +54,11 @@ struct rhash_head {
  * @buckets: size * hash buckets
  */
 struct bucket_table {
-       size_t                          size;
-       unsigned int                    locks_mask;
-       spinlock_t                      *locks;
-       struct rhash_head __rcu         *buckets[];
+       size_t                  size;
+       unsigned int            locks_mask;
+       spinlock_t              *locks;
+
+       struct rhash_head __rcu *buckets[] ____cacheline_aligned_in_smp;
 };
 
 typedef u32 (*rht_hashfn_t)(const void *data, u32 len, u32 seed);
@@ -78,12 +79,6 @@ struct rhashtable;
  * @locks_mul: Number of bucket locks to allocate per cpu (default: 128)
  * @hashfn: Function to hash key
  * @obj_hashfn: Function to hash object
- * @grow_decision: If defined, may return true if table should expand
- * @shrink_decision: If defined, may return true if table should shrink
- *
- * Note: when implementing the grow and shrink decision function, min/max
- * shift must be enforced, otherwise, resizing watermarks they set may be
- * useless.
  */
 struct rhashtable_params {
        size_t                  nelem_hint;
@@ -97,10 +92,6 @@ struct rhashtable_params {
        size_t                  locks_mul;
        rht_hashfn_t            hashfn;
        rht_obj_hashfn_t        obj_hashfn;
-       bool                    (*grow_decision)(const struct rhashtable *ht,
-                                                size_t new_size);
-       bool                    (*shrink_decision)(const struct rhashtable *ht,
-                                                  size_t new_size);
 };
 
 /**
@@ -192,9 +183,6 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params);
 void rhashtable_insert(struct rhashtable *ht, struct rhash_head *node);
 bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *node);
 
-bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size);
-bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size);
-
 int rhashtable_expand(struct rhashtable *ht);
 int rhashtable_shrink(struct rhashtable *ht);
 
index 6d77432..a419b65 100644 (file)
@@ -1625,11 +1625,11 @@ struct task_struct {
 
        /*
         * numa_faults_locality tracks if faults recorded during the last
-        * scan window were remote/local. The task scan period is adapted
-        * based on the locality of the faults with different weights
-        * depending on whether they were shared or private faults
+        * scan window were remote/local or failed to migrate. The task scan
+        * period is adapted based on the locality of the faults with different
+        * weights depending on whether they were shared or private faults
         */
-       unsigned long numa_faults_locality[2];
+       unsigned long numa_faults_locality[3];
 
        unsigned long numa_pages_migrated;
 #endif /* CONFIG_NUMA_BALANCING */
@@ -1719,6 +1719,7 @@ struct task_struct {
 #define TNF_NO_GROUP   0x02
 #define TNF_SHARED     0x04
 #define TNF_FAULT_LOCAL        0x08
+#define TNF_MIGRATE_FAIL 0x10
 
 #ifdef CONFIG_NUMA_BALANCING
 extern void task_numa_fault(int last_node, int node, int pages, int flags);
index baf3e1d..d10965f 100644 (file)
@@ -143,13 +143,13 @@ struct uart_port {
        unsigned char           iotype;                 /* io access style */
        unsigned char           unused1;
 
-#define UPIO_PORT              (0)                     /* 8b I/O port access */
-#define UPIO_HUB6              (1)                     /* Hub6 ISA card */
-#define UPIO_MEM               (2)                     /* 8b MMIO access */
-#define UPIO_MEM32             (3)                     /* 32b little endian */
-#define UPIO_MEM32BE           (4)                     /* 32b big endian */
-#define UPIO_AU                        (5)                     /* Au1x00 and RT288x type IO */
-#define UPIO_TSI               (6)                     /* Tsi108/109 type IO */
+#define UPIO_PORT              (SERIAL_IO_PORT)        /* 8b I/O port access */
+#define UPIO_HUB6              (SERIAL_IO_HUB6)        /* Hub6 ISA card */
+#define UPIO_MEM               (SERIAL_IO_MEM)         /* 8b MMIO access */
+#define UPIO_MEM32             (SERIAL_IO_MEM32)       /* 32b little endian */
+#define UPIO_AU                        (SERIAL_IO_AU)          /* Au1x00 and RT288x type IO */
+#define UPIO_TSI               (SERIAL_IO_TSI)         /* Tsi108/109 type IO */
+#define UPIO_MEM32BE           (SERIAL_IO_MEM32BE)     /* 32b big endian */
 
        unsigned int            read_status_mask;       /* driver specific */
        unsigned int            ignore_status_mask;     /* driver specific */
index 30007af..f54d665 100644 (file)
@@ -948,6 +948,13 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
        to->l4_hash = from->l4_hash;
 };
 
+static inline void skb_sender_cpu_clear(struct sk_buff *skb)
+{
+#ifdef CONFIG_XPS
+       skb->sender_cpu = 0;
+#endif
+}
+
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 {
index ed9489d..856d34d 100644 (file)
@@ -649,7 +649,7 @@ struct spi_transfer {
  * sequence completes.  On some systems, many such sequences can execute as
  * as single programmed DMA transfer.  On all systems, these messages are
  * queued, and might complete after transactions to other devices.  Messages
- * sent to a given spi_device are alway executed in FIFO order.
+ * sent to a given spi_device are always executed in FIFO order.
  *
  * The code that submits an spi_message (and its spi_transfers)
  * to the lower layers is responsible for managing its memory.
index c57d8ea..59a7889 100644 (file)
@@ -60,17 +60,17 @@ struct rpc_xprt;
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 void           rpc_register_sysctl(void);
 void           rpc_unregister_sysctl(void);
-int            sunrpc_debugfs_init(void);
+void           sunrpc_debugfs_init(void);
 void           sunrpc_debugfs_exit(void);
-int            rpc_clnt_debugfs_register(struct rpc_clnt *);
+void           rpc_clnt_debugfs_register(struct rpc_clnt *);
 void           rpc_clnt_debugfs_unregister(struct rpc_clnt *);
-int            rpc_xprt_debugfs_register(struct rpc_xprt *);
+void           rpc_xprt_debugfs_register(struct rpc_xprt *);
 void           rpc_xprt_debugfs_unregister(struct rpc_xprt *);
 #else
-static inline int
+static inline void
 sunrpc_debugfs_init(void)
 {
-       return 0;
+       return;
 }
 
 static inline void
@@ -79,10 +79,10 @@ sunrpc_debugfs_exit(void)
        return;
 }
 
-static inline int
+static inline void
 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
 {
-       return 0;
+       return;
 }
 
 static inline void
@@ -91,10 +91,10 @@ rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
        return;
 }
 
-static inline int
+static inline void
 rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
 {
-       return 0;
+       return;
 }
 
 static inline void
index fc52e30..5eac316 100644 (file)
@@ -314,6 +314,8 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
 }
 
 #endif
+
+#if IS_ENABLED(CONFIG_THERMAL)
 struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
                void *, struct thermal_zone_device_ops *,
                const struct thermal_zone_params *, int, int);
@@ -340,8 +342,58 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
                struct thermal_cooling_device *, int);
 void thermal_cdev_update(struct thermal_cooling_device *);
 void thermal_notify_framework(struct thermal_zone_device *, int);
-
-#ifdef CONFIG_NET
+#else
+static inline struct thermal_zone_device *thermal_zone_device_register(
+       const char *type, int trips, int mask, void *devdata,
+       struct thermal_zone_device_ops *ops,
+       const struct thermal_zone_params *tzp,
+       int passive_delay, int polling_delay)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_zone_device_unregister(
+       struct thermal_zone_device *tz)
+{ }
+static inline int thermal_zone_bind_cooling_device(
+       struct thermal_zone_device *tz, int trip,
+       struct thermal_cooling_device *cdev,
+       unsigned long upper, unsigned long lower)
+{ return -ENODEV; }
+static inline int thermal_zone_unbind_cooling_device(
+       struct thermal_zone_device *tz, int trip,
+       struct thermal_cooling_device *cdev)
+{ return -ENODEV; }
+static inline void thermal_zone_device_update(struct thermal_zone_device *tz)
+{ }
+static inline struct thermal_cooling_device *
+thermal_cooling_device_register(char *type, void *devdata,
+       const struct thermal_cooling_device_ops *ops)
+{ return ERR_PTR(-ENODEV); }
+static inline struct thermal_cooling_device *
+thermal_of_cooling_device_register(struct device_node *np,
+       char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_cooling_device_unregister(
+       struct thermal_cooling_device *cdev)
+{ }
+static inline struct thermal_zone_device *thermal_zone_get_zone_by_name(
+               const char *name)
+{ return ERR_PTR(-ENODEV); }
+static inline int thermal_zone_get_temp(
+               struct thermal_zone_device *tz, unsigned long *temp)
+{ return -ENODEV; }
+static inline int get_tz_trend(struct thermal_zone_device *tz, int trip)
+{ return -ENODEV; }
+static inline struct thermal_instance *
+get_thermal_instance(struct thermal_zone_device *tz,
+       struct thermal_cooling_device *cdev, int trip)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_cdev_update(struct thermal_cooling_device *cdev)
+{ }
+static inline void thermal_notify_framework(struct thermal_zone_device *tz,
+       int trip)
+{ }
+#endif /* CONFIG_THERMAL */
+
+#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL)
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
                                                enum events event);
 #else
index 07a0226..7188029 100644 (file)
@@ -98,6 +98,8 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
                        size_t maxsize, size_t *start);
 int iov_iter_npages(const struct iov_iter *i, int maxpages);
 
+const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags);
+
 static inline size_t iov_iter_count(struct iov_iter *i)
 {
        return i->count;
index 9bb547c..704a1ab 100644 (file)
@@ -190,8 +190,7 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
  * @num_ports: the number of different ports this device will have.
  * @bulk_in_size: minimum number of bytes to allocate for bulk-in buffer
  *     (0 = end-point size)
- * @bulk_out_size: minimum number of bytes to allocate for bulk-out buffer
- *     (0 = end-point size)
+ * @bulk_out_size: bytes to allocate for bulk-out buffer (0 = end-point size)
  * @calc_num_ports: pointer to a function to determine how many ports this
  *     device has dynamically.  It will be called after the probe()
  *     callback is called, but before attach()
index d9a4905..6e0ce8c 100644 (file)
@@ -227,9 +227,23 @@ struct skb_data {  /* skb->cb is one of these */
        struct urb              *urb;
        struct usbnet           *dev;
        enum skb_state          state;
-       size_t                  length;
+       long                    length;
+       unsigned long           packets;
 };
 
+/* Drivers that set FLAG_MULTI_PACKET must call this in their
+ * tx_fixup method before returning an skb.
+ */
+static inline void
+usbnet_set_skb_tx_stats(struct sk_buff *skb,
+                       unsigned long packets, long bytes_delta)
+{
+       struct skb_data *entry = (struct skb_data *) skb->cb;
+
+       entry->packets = packets;
+       entry->length = bytes_delta;
+}
+
 extern int usbnet_open(struct net_device *net);
 extern int usbnet_stop(struct net_device *net);
 extern netdev_tx_t usbnet_start_xmit(struct sk_buff *skb,
index 7d7acb3..0ec5983 100644 (file)
@@ -17,6 +17,7 @@ struct vm_area_struct;                /* vma defining user mapping in mm_types.h */
 #define VM_VPAGES              0x00000010      /* buffer for pages was vmalloc'ed */
 #define VM_UNINITIALIZED       0x00000020      /* vm_struct is not fully initialized */
 #define VM_NO_GUARD            0x00000040      /* don't add guard page */
+#define VM_KASAN               0x00000080      /* has allocated kasan shadow memory */
 /* bits [20..32] reserved for arch specific ioremap internals */
 
 /*
index 74db135..f597846 100644 (file)
@@ -70,7 +70,8 @@ enum {
        /* data contains off-queue information when !WORK_STRUCT_PWQ */
        WORK_OFFQ_FLAG_BASE     = WORK_STRUCT_COLOR_SHIFT,
 
-       WORK_OFFQ_CANCELING     = (1 << WORK_OFFQ_FLAG_BASE),
+       __WORK_OFFQ_CANCELING   = WORK_OFFQ_FLAG_BASE,
+       WORK_OFFQ_CANCELING     = (1 << __WORK_OFFQ_CANCELING),
 
        /*
         * When a work item is off queue, its high bits point to the last
index 0004833..b2dd371 100644 (file)
@@ -130,6 +130,7 @@ extern int vm_dirty_ratio;
 extern unsigned long vm_dirty_bytes;
 extern unsigned int dirty_writeback_interval;
 extern unsigned int dirty_expire_interval;
+extern unsigned int dirtytime_expire_interval;
 extern int vm_highmem_is_dirtyable;
 extern int block_dump;
 extern int laptop_mode;
@@ -146,6 +147,8 @@ extern int dirty_ratio_handler(struct ctl_table *table, int write,
 extern int dirty_bytes_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos);
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+                              void __user *buffer, size_t *lenp, loff_t *ppos);
 
 struct ctl_table;
 int dirty_writeback_centisecs_handler(struct ctl_table *, int,
index 1c1ad46..fe328c5 100644 (file)
@@ -171,7 +171,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos);
  * @return    Checksum of buffer.
  */
 
-u16 cfpkt_iterate(struct cfpkt *pkt,
+int cfpkt_iterate(struct cfpkt *pkt,
                u16 (*iter_func)(u16 chks, void *buf, u16 len),
                u16 data);
 
index a8ae4e7..0fb99a2 100644 (file)
@@ -481,6 +481,7 @@ void dst_init(void);
 enum {
        XFRM_LOOKUP_ICMP = 1 << 0,
        XFRM_LOOKUP_QUEUE = 1 << 1,
+       XFRM_LOOKUP_KEEP_DST_REF = 1 << 2,
 };
 
 struct flowi;
index 025c61c..6cc1eaf 100644 (file)
@@ -453,22 +453,6 @@ static __inline__ void inet_reset_saddr(struct sock *sk)
 
 #endif
 
-static inline int sk_mc_loop(struct sock *sk)
-{
-       if (!sk)
-               return 1;
-       switch (sk->sk_family) {
-       case AF_INET:
-               return inet_sk(sk)->mc_loop;
-#if IS_ENABLED(CONFIG_IPV6)
-       case AF_INET6:
-               return inet6_sk(sk)->mc_loop;
-#endif
-       }
-       WARN_ON(1);
-       return 1;
-}
-
 bool ip_call_ra_chain(struct sk_buff *skb);
 
 /*
index 1d09b46..eda131d 100644 (file)
@@ -174,7 +174,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 
 static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
 {
-       struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+       struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
+                               inet6_sk(skb->sk) : NULL;
 
        return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ?
               skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
index 534e1f2..57639fc 100644 (file)
@@ -79,6 +79,16 @@ void nf_log_packet(struct net *net,
                   const struct nf_loginfo *li,
                   const char *fmt, ...);
 
+__printf(8, 9)
+void nf_log_trace(struct net *net,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *li,
+                 const char *fmt, ...);
+
 struct nf_log_buf;
 
 struct nf_log_buf *nf_log_buf_open(void);
index 9eaaa78..decb9a0 100644 (file)
@@ -119,6 +119,22 @@ int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
                           const struct nft_data *data,
                           enum nft_data_types type);
 
+
+/**
+ *     struct nft_userdata - user defined data associated with an object
+ *
+ *     @len: length of the data
+ *     @data: content
+ *
+ *     The presence of user data is indicated in an object specific fashion,
+ *     so a length of zero can't occur and the value "len" indicates data
+ *     of length len + 1.
+ */
+struct nft_userdata {
+       u8                      len;
+       unsigned char           data[0];
+};
+
 /**
  *     struct nft_set_elem - generic representation of set elements
  *
@@ -380,7 +396,7 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
  *     @handle: rule handle
  *     @genmask: generation mask
  *     @dlen: length of expression data
- *     @ulen: length of user data (used for comments)
+ *     @udata: user data is appended to the rule
  *     @data: expression data
  */
 struct nft_rule {
@@ -388,7 +404,7 @@ struct nft_rule {
        u64                             handle:42,
                                        genmask:2,
                                        dlen:12,
-                                       ulen:8;
+                                       udata:1;
        unsigned char                   data[]
                __attribute__((aligned(__alignof__(struct nft_expr))));
 };
@@ -476,7 +492,7 @@ static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule)
        return (struct nft_expr *)&rule->data[rule->dlen];
 }
 
-static inline void *nft_userdata(const struct nft_rule *rule)
+static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
 {
        return (void *)&rule->data[rule->dlen];
 }
index ab186b1..e4079c2 100644 (file)
@@ -1762,6 +1762,8 @@ struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie);
 
 struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie);
 
+bool sk_mc_loop(struct sock *sk);
+
 static inline bool sk_can_gso(const struct sock *sk)
 {
        return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type);
index eabd3a0..c73e7ab 100644 (file)
@@ -91,6 +91,7 @@ struct vxlanhdr {
 
 #define VXLAN_N_VID     (1u << 24)
 #define VXLAN_VID_MASK  (VXLAN_N_VID - 1)
+#define VXLAN_VNI_MASK  (VXLAN_VID_MASK << 8)
 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
 
 struct vxlan_metadata {
index 0210797..dc10c52 100644 (file)
@@ -92,7 +92,7 @@
 #define                AT91_DDRSDRC_UPD_MR     (3 << 20)        /* Update load mode register and extended mode register */
 
 #define AT91_DDRSDRC_MDR       0x20    /* Memory Device Register */
-#define                AT91_DDRSDRC_MD         (3 << 0)                /* Memory Device Type */
+#define                AT91_DDRSDRC_MD         (7 << 0)        /* Memory Device Type */
 #define                        AT91_DDRSDRC_MD_SDR             0
 #define                        AT91_DDRSDRC_MD_LOW_POWER_SDR   1
 #define                        AT91_DDRSDRC_MD_LOW_POWER_DDR   3
index 3c45f39..c704357 100644 (file)
@@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p)
        return snd_pcm_format_physical_width(params_format(p));
 }
 
+static inline void
+params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
+{
+       snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT),
+               (__force int)fmt);
+}
+
 #endif /* __SOUND_PCM_PARAMS_H */
index bd31119..b7d6051 100644 (file)
@@ -14,6 +14,7 @@
 struct rt5670_platform_data {
        int jd_mode;
        bool in2_diff;
+       bool dev_gpio;
 
        bool dmic_en;
        unsigned int dmic1_data_pin;
index 8d7416e..d3a76b5 100644 (file)
@@ -440,7 +440,6 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
        struct snd_soc_dapm_widget_list **list);
 
-struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol);
 struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
        struct snd_kcontrol *kcontrol);
 
@@ -586,8 +585,6 @@ struct snd_soc_dapm_update {
 /* DAPM context */
 struct snd_soc_dapm_context {
        enum snd_soc_bias_level bias_level;
-       enum snd_soc_bias_level suspend_bias_level;
-       struct delayed_work delayed_work;
        unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
        /* Go to BIAS_OFF in suspend if the DAPM context is idle */
        unsigned int suspend_bias_off:1;
index 98f2ade..8060590 100644 (file)
@@ -135,7 +135,7 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
 
 /* internal use only */
 int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
-int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
+void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
 int soc_dpcm_runtime_update(struct snd_soc_card *);
 
 int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
index 0d1ade1..92b92ac 100644 (file)
@@ -450,8 +450,10 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
                      struct snd_soc_dai *dai);
 
 /* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
-                    struct snd_soc_jack *jack);
+int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
+       struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
+       unsigned int num_pins);
+
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
                          struct snd_soc_jack_pin *pins);
@@ -659,7 +661,7 @@ struct snd_soc_jack_gpio {
 struct snd_soc_jack {
        struct mutex mutex;
        struct snd_jack *jack;
-       struct snd_soc_codec *codec;
+       struct snd_soc_card *card;
        struct list_head pins;
        int status;
        struct blocking_notifier_head notifier;
@@ -954,6 +956,9 @@ struct snd_soc_dai_link {
        unsigned int symmetric_channels:1;
        unsigned int symmetric_samplebits:1;
 
+       /* Mark this pcm with non atomic ops */
+       bool nonatomic;
+
        /* Do not create a PCM for this DAI link (Backend link) */
        unsigned int no_pcm:1;
 
@@ -1071,11 +1076,16 @@ struct snd_soc_card {
 
        /*
         * Card-specific routes and widgets.
+        * Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in.
         */
        const struct snd_soc_dapm_widget *dapm_widgets;
        int num_dapm_widgets;
        const struct snd_soc_dapm_route *dapm_routes;
        int num_dapm_routes;
+       const struct snd_soc_dapm_widget *of_dapm_widgets;
+       int num_of_dapm_widgets;
+       const struct snd_soc_dapm_route *of_dapm_routes;
+       int num_of_dapm_routes;
        bool fully_routed;
 
        struct work_struct deferred_resume_work;
@@ -1258,6 +1268,19 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
        return component->dapm_ptr;
 }
 
+/**
+ * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
+ * @kcontrol: The kcontrol
+ *
+ * This function must only be used on DAPM contexts that are known to be part of
+ * a CODEC (e.g. in a CODEC driver). Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(
+       struct snd_kcontrol *kcontrol)
+{
+       return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol));
+}
+
 /* codec IO */
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
index db81c65..d61be72 100644 (file)
@@ -111,6 +111,7 @@ void        array_free(void *array, int n);
 void   target_core_setup_sub_cits(struct se_subsystem_api *);
 
 /* attribute helpers from target_core_device.c for backend drivers */
+bool   se_dev_check_wce(struct se_device *);
 int    se_dev_set_max_unmap_lba_count(struct se_device *, u32);
 int    se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
 int    se_dev_set_unmap_granularity(struct se_device *, u32);
index 23d5615..22317d2 100644 (file)
@@ -7,27 +7,26 @@
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
-struct device;
-struct regmap;
+#include "../../../drivers/base/regmap/internal.h"
 
 /*
  * Log register events
  */
 DECLARE_EVENT_CLASS(regmap_reg,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val),
+       TP_ARGS(map, reg, val),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   reg             )
-               __field(        unsigned int,   val             )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   reg                     )
+               __field(        unsigned int,   val                     )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->reg = reg;
                __entry->val = val;
        ),
@@ -39,45 +38,45 @@ DECLARE_EVENT_CLASS(regmap_reg,
 
 DEFINE_EVENT(regmap_reg, regmap_reg_write,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DEFINE_EVENT(regmap_reg, regmap_reg_read,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DEFINE_EVENT(regmap_reg, regmap_reg_read_cache,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DECLARE_EVENT_CLASS(regmap_block,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count),
+       TP_ARGS(map, reg, count),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   reg             )
-               __field(        int,            count           )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   reg                     )
+               __field(        int,            count                   )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->reg = reg;
                __entry->count = count;
        ),
@@ -89,48 +88,48 @@ DECLARE_EVENT_CLASS(regmap_block,
 
 DEFINE_EVENT(regmap_block, regmap_hw_read_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_read_done,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_write_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_write_done,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 TRACE_EVENT(regcache_sync,
 
-       TP_PROTO(struct device *dev, const char *type,
+       TP_PROTO(struct regmap *map, const char *type,
                 const char *status),
 
-       TP_ARGS(dev, type, status),
+       TP_ARGS(map, type, status),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __string(       status,         status          )
-               __string(       type,           type            )
-               __field(        int,            type            )
+               __string(       name,           regmap_name(map)        )
+               __string(       status,         status                  )
+               __string(       type,           type                    )
+               __field(        int,            type                    )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __assign_str(status, status);
                __assign_str(type, type);
        ),
@@ -141,17 +140,17 @@ TRACE_EVENT(regcache_sync,
 
 DECLARE_EVENT_CLASS(regmap_bool,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag),
+       TP_ARGS(map, flag),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        int,            flag            )
+               __string(       name,           regmap_name(map)        )
+               __field(        int,            flag                    )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->flag = flag;
        ),
 
@@ -161,32 +160,32 @@ DECLARE_EVENT_CLASS(regmap_bool,
 
 DEFINE_EVENT(regmap_bool, regmap_cache_only,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag)
+       TP_ARGS(map, flag)
 
 );
 
 DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag)
+       TP_ARGS(map, flag)
 
 );
 
 DECLARE_EVENT_CLASS(regmap_async,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev),
+       TP_ARGS(map),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
+               __string(       name,           regmap_name(map)        )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
        ),
 
        TP_printk("%s", __get_str(name))
@@ -194,50 +193,50 @@ DECLARE_EVENT_CLASS(regmap_async,
 
 DEFINE_EVENT(regmap_block, regmap_async_write_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_io_complete,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_complete_start,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_complete_done,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 TRACE_EVENT(regcache_drop_region,
 
-       TP_PROTO(struct device *dev, unsigned int from,
+       TP_PROTO(struct regmap *map, unsigned int from,
                 unsigned int to),
 
-       TP_ARGS(dev, from, to),
+       TP_ARGS(map, from, to),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   from            )
-               __field(        unsigned int,   to              )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   from                    )
+               __field(        unsigned int,   to                      )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->from = from;
                __entry->to = to;
        ),
index b0a8130..2f62ab2 100644 (file)
@@ -973,7 +973,8 @@ struct input_keymap_entry {
  */
 #define MT_TOOL_FINGER         0
 #define MT_TOOL_PEN            1
-#define MT_TOOL_MAX            1
+#define MT_TOOL_PALM           2
+#define MT_TOOL_MAX            2
 
 /*
  * Values describing the status of a force-feedback effect
index 4742f2c..d3bd6ff 100644 (file)
@@ -47,7 +47,7 @@
  * exported filesystem.
  */
 #define        NFSEXP_V4ROOT           0x10000
-#define NFSEXP_NOPNFS          0x20000
+#define NFSEXP_PNFS            0x20000
 
 /* All flags that we claim to support.  (Note we don't support NOACL.) */
 #define NFSEXP_ALLFLAGS                0x3FE7F
index 5e0d0ed..25331f9 100644 (file)
@@ -65,6 +65,10 @@ struct serial_struct {
 #define SERIAL_IO_PORT 0
 #define SERIAL_IO_HUB6 1
 #define SERIAL_IO_MEM  2
+#define SERIAL_IO_MEM32          3
+#define SERIAL_IO_AU     4
+#define SERIAL_IO_TSI    5
+#define SERIAL_IO_MEM32BE 6
 
 #define UART_CLEAR_FIFO                0x01
 #define UART_USE_FIFO          0x02
index 19d5219..242cf0c 100644 (file)
@@ -9,3 +9,4 @@ header-y += tc_pedit.h
 header-y += tc_skbedit.h
 header-y += tc_vlan.h
 header-y += tc_bpf.h
+header-y += tc_connmark.h
index 3c53eec..19c66fc 100644 (file)
@@ -60,7 +60,7 @@ struct virtio_blk_config {
        __u32 size_max;
        /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
        __u32 seg_max;
-       /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
+       /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
        struct virtio_blk_geometry {
                __u16 cylinders;
                __u8 heads;
@@ -119,7 +119,11 @@ struct virtio_blk_config {
 #define VIRTIO_BLK_T_BARRIER   0x80000000
 #endif /* !VIRTIO_BLK_NO_LEGACY */
 
-/* This is the first element of the read scatter-gather list. */
+/*
+ * This comes first in the read scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
+ * this is the first element of the read scatter-gather list.
+ */
 struct virtio_blk_outhdr {
        /* VIRTIO_BLK_T* */
        __virtio32 type;
index 42b9370..cc18ef8 100644 (file)
 
 #include <linux/virtio_types.h>
 
-#define VIRTIO_SCSI_CDB_SIZE   32
-#define VIRTIO_SCSI_SENSE_SIZE 96
+/* Default values of the CDB and sense data size configuration fields */
+#define VIRTIO_SCSI_CDB_DEFAULT_SIZE   32
+#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96
+
+#ifndef VIRTIO_SCSI_CDB_SIZE
+#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE
+#endif
+#ifndef VIRTIO_SCSI_SENSE_SIZE
+#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE
+#endif
 
 /* SCSI command request, followed by data-out */
 struct virtio_scsi_cmd_req {
index 60de61f..c8ed15d 100644 (file)
@@ -689,6 +689,7 @@ struct omapdss_dsi_ops {
 };
 
 struct omap_dss_device {
+       struct kobject kobj;
        struct device *dev;
 
        struct module *owner;
index 7491ee5..8333821 100644 (file)
@@ -46,4 +46,30 @@ static inline efi_system_table_t __init *xen_efi_probe(void)
 }
 #endif
 
+#ifdef CONFIG_PREEMPT
+
+static inline void xen_preemptible_hcall_begin(void)
+{
+}
+
+static inline void xen_preemptible_hcall_end(void)
+{
+}
+
+#else
+
+DECLARE_PER_CPU(bool, xen_in_preemptible_hcall);
+
+static inline void xen_preemptible_hcall_begin(void)
+{
+       __this_cpu_write(xen_in_preemptible_hcall, true);
+}
+
+static inline void xen_preemptible_hcall_end(void)
+{
+       __this_cpu_write(xen_in_preemptible_hcall, false);
+}
+
+#endif /* CONFIG_PREEMPT */
+
 #endif /* INCLUDE_XEN_OPS_H */
index b78f21c..b0f1c9e 100644 (file)
@@ -114,9 +114,9 @@ int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
                                           const char *mod_name);
 
 #define xenbus_register_frontend(drv) \
-       __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME);
+       __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME)
 #define xenbus_register_backend(drv) \
-       __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME);
+       __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME)
 
 void xenbus_unregister_driver(struct xenbus_driver *drv);
 
index 1d1fe93..fc7f474 100644 (file)
@@ -548,9 +548,6 @@ static void update_domain_attr_tree(struct sched_domain_attr *dattr,
 
        rcu_read_lock();
        cpuset_for_each_descendant_pre(cp, pos_css, root_cs) {
-               if (cp == root_cs)
-                       continue;
-
                /* skip the whole subtree if @cp doesn't have any CPU */
                if (cpumask_empty(cp->cpus_allowed)) {
                        pos_css = css_rightmost_descendant(pos_css);
@@ -873,7 +870,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct cpumask *new_cpus)
                 * If it becomes empty, inherit the effective mask of the
                 * parent, which is guaranteed to have some CPUs.
                 */
-               if (cpumask_empty(new_cpus))
+               if (cgroup_on_dfl(cp->css.cgroup) && cpumask_empty(new_cpus))
                        cpumask_copy(new_cpus, parent->effective_cpus);
 
                /* Skip the whole subtree if the cpumask remains the same. */
@@ -1129,7 +1126,7 @@ static void update_nodemasks_hier(struct cpuset *cs, nodemask_t *new_mems)
                 * If it becomes empty, inherit the effective mask of the
                 * parent, which is guaranteed to have some MEMs.
                 */
-               if (nodes_empty(*new_mems))
+               if (cgroup_on_dfl(cp->css.cgroup) && nodes_empty(*new_mems))
                        *new_mems = parent->effective_mems;
 
                /* Skip the whole subtree if the nodemask remains the same. */
@@ -1979,7 +1976,9 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
 
        spin_lock_irq(&callback_lock);
        cs->mems_allowed = parent->mems_allowed;
+       cs->effective_mems = parent->mems_allowed;
        cpumask_copy(cs->cpus_allowed, parent->cpus_allowed);
+       cpumask_copy(cs->effective_cpus, parent->cpus_allowed);
        spin_unlock_irq(&callback_lock);
 out_unlock:
        mutex_unlock(&cpuset_mutex);
index f04daab..2fabc06 100644 (file)
@@ -3591,7 +3591,7 @@ static void put_event(struct perf_event *event)
        ctx = perf_event_ctx_lock_nested(event, SINGLE_DEPTH_NESTING);
        WARN_ON_ONCE(ctx->parent_ctx);
        perf_remove_from_context(event, true);
-       mutex_unlock(&ctx->mutex);
+       perf_event_ctx_unlock(event, ctx);
 
        _free_event(event);
 }
@@ -4574,6 +4574,13 @@ static void perf_pending_event(struct irq_work *entry)
 {
        struct perf_event *event = container_of(entry,
                        struct perf_event, pending);
+       int rctx;
+
+       rctx = perf_swevent_get_recursion_context();
+       /*
+        * If we 'fail' here, that's OK, it means recursion is already disabled
+        * and we won't recurse 'further'.
+        */
 
        if (event->pending_disable) {
                event->pending_disable = 0;
@@ -4584,6 +4591,9 @@ static void perf_pending_event(struct irq_work *entry)
                event->pending_wakeup = 0;
                perf_event_wakeup(event);
        }
+
+       if (rctx >= 0)
+               perf_swevent_put_recursion_context(rctx);
 }
 
 /*
index 196a06f..886d09e 100644 (file)
@@ -1474,8 +1474,13 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
         * otherwise we'll have trouble later trying to figure out
         * which interrupt is which (messes up the interrupt freeing
         * logic etc).
+        *
+        * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and
+        * it cannot be set along with IRQF_NO_SUSPEND.
         */
-       if ((irqflags & IRQF_SHARED) && !dev_id)
+       if (((irqflags & IRQF_SHARED) && !dev_id) ||
+           (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||
+           ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))
                return -EINVAL;
 
        desc = irq_to_desc(irq);
index 3ca5325..5204a6d 100644 (file)
@@ -43,9 +43,12 @@ void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action)
 
        if (action->flags & IRQF_NO_SUSPEND)
                desc->no_suspend_depth++;
+       else if (action->flags & IRQF_COND_SUSPEND)
+               desc->cond_suspend_depth++;
 
        WARN_ON_ONCE(desc->no_suspend_depth &&
-                    desc->no_suspend_depth != desc->nr_actions);
+                    (desc->no_suspend_depth +
+                       desc->cond_suspend_depth) != desc->nr_actions);
 }
 
 /*
@@ -61,6 +64,8 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action)
 
        if (action->flags & IRQF_NO_SUSPEND)
                desc->no_suspend_depth--;
+       else if (action->flags & IRQF_COND_SUSPEND)
+               desc->cond_suspend_depth--;
 }
 
 static bool suspend_device_irq(struct irq_desc *desc, int irq)
index ff7f47d..3f9f1d6 100644 (file)
@@ -89,16 +89,28 @@ static bool klp_is_object_loaded(struct klp_object *obj)
 /* sets obj->mod if object is not vmlinux and module is found */
 static void klp_find_object_module(struct klp_object *obj)
 {
+       struct module *mod;
+
        if (!klp_is_module(obj))
                return;
 
        mutex_lock(&module_mutex);
        /*
-        * We don't need to take a reference on the module here because we have
-        * the klp_mutex, which is also taken by the module notifier.  This
-        * prevents any module from unloading until we release the klp_mutex.
+        * We do not want to block removal of patched modules and therefore
+        * we do not take a reference here. The patches are removed by
+        * a going module handler instead.
+        */
+       mod = find_module(obj->name);
+       /*
+        * Do not mess work of the module coming and going notifiers.
+        * Note that the patch might still be needed before the going handler
+        * is called. Module functions can be called even in the GOING state
+        * until mod->exit() finishes. This is especially important for
+        * patches that modify semantic of the functions.
         */
-       obj->mod = find_module(obj->name);
+       if (mod && mod->klp_alive)
+               obj->mod = mod;
+
        mutex_unlock(&module_mutex);
 }
 
@@ -248,11 +260,12 @@ static int klp_find_external_symbol(struct module *pmod, const char *name,
        /* first, check if it's an exported symbol */
        preempt_disable();
        sym = find_symbol(name, NULL, NULL, true, true);
-       preempt_enable();
        if (sym) {
                *addr = sym->value;
+               preempt_enable();
                return 0;
        }
+       preempt_enable();
 
        /* otherwise check if it's in another .o within the patch module */
        return klp_find_object_symbol(pmod->name, name, addr);
@@ -314,12 +327,12 @@ static void notrace klp_ftrace_handler(unsigned long ip,
        rcu_read_lock();
        func = list_first_or_null_rcu(&ops->func_stack, struct klp_func,
                                      stack_node);
-       rcu_read_unlock();
-
        if (WARN_ON_ONCE(!func))
-               return;
+               goto unlock;
 
        klp_arch_set_pc(regs, (unsigned long)func->new_func);
+unlock:
+       rcu_read_unlock();
 }
 
 static int klp_disable_func(struct klp_func *func)
@@ -731,7 +744,7 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
        func->state = KLP_DISABLED;
 
        return kobject_init_and_add(&func->kobj, &klp_ktype_func,
-                                   obj->kobj, func->old_name);
+                                   obj->kobj, "%s", func->old_name);
 }
 
 /* parts of the initialization that is done only when the object is loaded */
@@ -766,6 +779,7 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
                return -EINVAL;
 
        obj->state = KLP_DISABLED;
+       obj->mod = NULL;
 
        klp_find_object_module(obj);
 
@@ -807,7 +821,7 @@ static int klp_init_patch(struct klp_patch *patch)
        patch->state = KLP_DISABLED;
 
        ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch,
-                                  klp_root_kobj, patch->mod->name);
+                                  klp_root_kobj, "%s", patch->mod->name);
        if (ret)
                goto unlock;
 
@@ -960,6 +974,15 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action,
 
        mutex_lock(&klp_mutex);
 
+       /*
+        * Each module has to know that the notifier has been called.
+        * We never know what module will get patched by a new patch.
+        */
+       if (action == MODULE_STATE_COMING)
+               mod->klp_alive = true;
+       else /* MODULE_STATE_GOING */
+               mod->klp_alive = false;
+
        list_for_each_entry(patch, &klp_patches, list) {
                for (obj = patch->objs; obj->funcs; obj++) {
                        if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
index 88d0d44..ba77ab5 100644 (file)
@@ -633,7 +633,7 @@ static int count_matching_names(struct lock_class *new_class)
        if (!new_class->name)
                return 0;
 
-       list_for_each_entry(class, &all_lock_classes, lock_entry) {
+       list_for_each_entry_rcu(class, &all_lock_classes, lock_entry) {
                if (new_class->key - new_class->subclass == class->key)
                        return class->name_version;
                if (class->name && !strcmp(class->name, new_class->name))
@@ -700,10 +700,12 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
        hash_head = classhashentry(key);
 
        /*
-        * We can walk the hash lockfree, because the hash only
-        * grows, and we are careful when adding entries to the end:
+        * We do an RCU walk of the hash, see lockdep_free_key_range().
         */
-       list_for_each_entry(class, hash_head, hash_entry) {
+       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+               return NULL;
+
+       list_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key) {
                        /*
                         * Huh! same key, different name? Did someone trample
@@ -728,7 +730,8 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        struct lockdep_subclass_key *key;
        struct list_head *hash_head;
        struct lock_class *class;
-       unsigned long flags;
+
+       DEBUG_LOCKS_WARN_ON(!irqs_disabled());
 
        class = look_up_lock_class(lock, subclass);
        if (likely(class))
@@ -750,28 +753,26 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        key = lock->key->subkeys + subclass;
        hash_head = classhashentry(key);
 
-       raw_local_irq_save(flags);
        if (!graph_lock()) {
-               raw_local_irq_restore(flags);
                return NULL;
        }
        /*
         * We have to do the hash-walk again, to avoid races
         * with another CPU:
         */
-       list_for_each_entry(class, hash_head, hash_entry)
+       list_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key)
                        goto out_unlock_set;
+       }
+
        /*
         * Allocate a new key from the static array, and add it to
         * the hash:
         */
        if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
                if (!debug_locks_off_graph_unlock()) {
-                       raw_local_irq_restore(flags);
                        return NULL;
                }
-               raw_local_irq_restore(flags);
 
                print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!");
                dump_stack();
@@ -798,7 +799,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
 
        if (verbose(class)) {
                graph_unlock();
-               raw_local_irq_restore(flags);
 
                printk("\nnew class %p: %s", class->key, class->name);
                if (class->name_version > 1)
@@ -806,15 +806,12 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
                printk("\n");
                dump_stack();
 
-               raw_local_irq_save(flags);
                if (!graph_lock()) {
-                       raw_local_irq_restore(flags);
                        return NULL;
                }
        }
 out_unlock_set:
        graph_unlock();
-       raw_local_irq_restore(flags);
 
 out_set_class_cache:
        if (!subclass || force)
@@ -870,11 +867,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
        entry->distance = distance;
        entry->trace = *trace;
        /*
-        * Since we never remove from the dependency list, the list can
-        * be walked lockless by other CPUs, it's only allocation
-        * that must be protected by the spinlock. But this also means
-        * we must make new entries visible only once writes to the
-        * entry become visible - hence the RCU op:
+        * Both allocation and removal are done under the graph lock; but
+        * iteration is under RCU-sched; see look_up_lock_class() and
+        * lockdep_free_key_range().
         */
        list_add_tail_rcu(&entry->entry, head);
 
@@ -1025,7 +1020,9 @@ static int __bfs(struct lock_list *source_entry,
                else
                        head = &lock->class->locks_before;
 
-               list_for_each_entry(entry, head, entry) {
+               DEBUG_LOCKS_WARN_ON(!irqs_disabled());
+
+               list_for_each_entry_rcu(entry, head, entry) {
                        if (!lock_accessed(entry)) {
                                unsigned int cq_depth;
                                mark_lock_accessed(entry, lock);
@@ -2022,7 +2019,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
         * We can walk it lock-free, because entries only get added
         * to the hash:
         */
-       list_for_each_entry(chain, hash_head, entry) {
+       list_for_each_entry_rcu(chain, hash_head, entry) {
                if (chain->chain_key == chain_key) {
 cache_hit:
                        debug_atomic_inc(chain_lookup_hits);
@@ -2996,8 +2993,18 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
        if (unlikely(!debug_locks))
                return;
 
-       if (subclass)
+       if (subclass) {
+               unsigned long flags;
+
+               if (DEBUG_LOCKS_WARN_ON(current->lockdep_recursion))
+                       return;
+
+               raw_local_irq_save(flags);
+               current->lockdep_recursion = 1;
                register_lock_class(lock, subclass, 1);
+               current->lockdep_recursion = 0;
+               raw_local_irq_restore(flags);
+       }
 }
 EXPORT_SYMBOL_GPL(lockdep_init_map);
 
@@ -3887,9 +3894,17 @@ static inline int within(const void *addr, void *start, unsigned long size)
        return addr >= start && addr < start + size;
 }
 
+/*
+ * Used in module.c to remove lock classes from memory that is going to be
+ * freed; and possibly re-used by other modules.
+ *
+ * We will have had one sync_sched() before getting here, so we're guaranteed
+ * nobody will look up these exact classes -- they're properly dead but still
+ * allocated.
+ */
 void lockdep_free_key_range(void *start, unsigned long size)
 {
-       struct lock_class *class, *next;
+       struct lock_class *class;
        struct list_head *head;
        unsigned long flags;
        int i;
@@ -3905,7 +3920,7 @@ void lockdep_free_key_range(void *start, unsigned long size)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry) {
+               list_for_each_entry_rcu(class, head, hash_entry) {
                        if (within(class->key, start, size))
                                zap_class(class);
                        else if (within(class->name, start, size))
@@ -3916,11 +3931,25 @@ void lockdep_free_key_range(void *start, unsigned long size)
        if (locked)
                graph_unlock();
        raw_local_irq_restore(flags);
+
+       /*
+        * Wait for any possible iterators from look_up_lock_class() to pass
+        * before continuing to free the memory they refer to.
+        *
+        * sync_sched() is sufficient because the read-side is IRQ disable.
+        */
+       synchronize_sched();
+
+       /*
+        * XXX at this point we could return the resources to the pool;
+        * instead we leak them. We would need to change to bitmap allocators
+        * instead of the linear allocators we have now.
+        */
 }
 
 void lockdep_reset_lock(struct lockdep_map *lock)
 {
-       struct lock_class *class, *next;
+       struct lock_class *class;
        struct list_head *head;
        unsigned long flags;
        int i, j;
@@ -3948,7 +3977,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry) {
+               list_for_each_entry_rcu(class, head, hash_entry) {
                        int match = 0;
 
                        for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++)
index e16e554..6357265 100644 (file)
@@ -1193,6 +1193,7 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
                ret = __rt_mutex_slowlock(lock, state, timeout, &waiter);
 
        if (unlikely(ret)) {
+               __set_current_state(TASK_RUNNING);
                if (rt_mutex_has_waiters(lock))
                        remove_waiter(lock, &waiter);
                rt_mutex_handle_deadlock(ret, chwalk, &waiter);
index b34813f..99fdf94 100644 (file)
@@ -56,7 +56,6 @@
 #include <linux/async.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
-#include <linux/kasan.h>
 #include <linux/jump_label.h>
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
@@ -1814,7 +1813,6 @@ static void unset_module_init_ro_nx(struct module *mod) { }
 void __weak module_memfree(void *module_region)
 {
        vfree(module_region);
-       kasan_module_free(module_region);
 }
 
 void __weak module_arch_cleanup(struct module *mod)
@@ -1867,7 +1865,7 @@ static void free_module(struct module *mod)
        kfree(mod->args);
        percpu_modfree(mod);
 
-       /* Free lock-classes: */
+       /* Free lock-classes; relies on the preceding sync_rcu(). */
        lockdep_free_key_range(mod->module_core, mod->core_size);
 
        /* Finally, free the core (containing the module structure) */
@@ -2313,11 +2311,13 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
        info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
        mod->core_size += strtab_size;
+       mod->core_size = debug_align(mod->core_size);
 
        /* Put string table section at end of init part of module. */
        strsect->sh_flags |= SHF_ALLOC;
        strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
                                         info->index.str) | INIT_OFFSET_MASK;
+       mod->init_size = debug_align(mod->init_size);
        pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
 }
 
@@ -3349,9 +3349,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
        module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
 
-       /* Free lock-classes: */
-       lockdep_free_key_range(mod->module_core, mod->core_size);
-
        /* we can't deallocate the module until we clear memory protection */
        unset_module_init_ro_nx(mod);
        unset_module_core_ro_nx(mod);
@@ -3375,6 +3372,9 @@ static int load_module(struct load_info *info, const char __user *uargs,
        synchronize_rcu();
        mutex_unlock(&module_mutex);
  free_module:
+       /* Free lock-classes; relies on the preceding sync_rcu() */
+       lockdep_free_key_range(mod->module_core, mod->core_size);
+
        module_deallocate(mod, info);
  free_copy:
        free_copy(info);
index cbd69d8..2ca4a8b 100644 (file)
@@ -3,7 +3,7 @@
 
 struct console_cmdline
 {
-       char    name[8];                        /* Name of the driver       */
+       char    name[16];                       /* Name of the driver       */
        int     index;                          /* Minor dev. to use        */
        char    *options;                       /* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
index 01cfd69..bb0635b 100644 (file)
@@ -2464,6 +2464,7 @@ void register_console(struct console *newcon)
        for (i = 0, c = console_cmdline;
             i < MAX_CMDLINECONSOLES && c->name[0];
             i++, c++) {
+               BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
                if (strcmp(c->name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
index f0f831e..62671f5 100644 (file)
@@ -3034,6 +3034,8 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        } else {
                if (dl_prio(oldprio))
                        p->dl.dl_boosted = 0;
+               if (rt_prio(oldprio))
+                       p->rt.timeout = 0;
                p->sched_class = &fair_sched_class;
        }
 
index 7ce18f3..bcfe320 100644 (file)
@@ -1609,9 +1609,11 @@ static void update_task_scan_period(struct task_struct *p,
        /*
         * If there were no record hinting faults then either the task is
         * completely idle or all activity is areas that are not of interest
-        * to automatic numa balancing. Scan slower
+        * to automatic numa balancing. Related to that, if there were failed
+        * migration then it implies we are migrating too quickly or the local
+        * node is overloaded. In either case, scan slower
         */
-       if (local + shared == 0) {
+       if (local + shared == 0 || p->numa_faults_locality[2]) {
                p->numa_scan_period = min(p->numa_scan_period_max,
                        p->numa_scan_period << 1);
 
@@ -2080,6 +2082,8 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
 
        if (migrated)
                p->numa_pages_migrated += pages;
+       if (flags & TNF_MIGRATE_FAIL)
+               p->numa_faults_locality[2] += pages;
 
        p->numa_faults[task_faults_idx(NUMA_MEMBUF, mem_node, priv)] += pages;
        p->numa_faults[task_faults_idx(NUMA_CPUBUF, cpu_node, priv)] += pages;
index 94b2d7b..80014a1 100644 (file)
@@ -82,6 +82,7 @@ static void cpuidle_idle_call(void)
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int next_state, entered_state;
        unsigned int broadcast;
+       bool reflect;
 
        /*
         * Check if the idle task must be rescheduled. If it is the
@@ -105,6 +106,9 @@ static void cpuidle_idle_call(void)
         */
        rcu_idle_enter();
 
+       if (cpuidle_not_available(drv, dev))
+               goto use_default;
+
        /*
         * Suspend-to-idle ("freeze") is a system state in which all user space
         * has been frozen, all I/O devices have been suspended and the only
@@ -115,30 +119,24 @@ static void cpuidle_idle_call(void)
         * until a proper wakeup interrupt happens.
         */
        if (idle_should_freeze()) {
-               cpuidle_enter_freeze();
-               local_irq_enable();
-               goto exit_idle;
-       }
+               entered_state = cpuidle_enter_freeze(drv, dev);
+               if (entered_state >= 0) {
+                       local_irq_enable();
+                       goto exit_idle;
+               }
 
-       /*
-        * Ask the cpuidle framework to choose a convenient idle state.
-        * Fall back to the default arch idle method on errors.
-        */
-       next_state = cpuidle_select(drv, dev);
-       if (next_state < 0) {
-use_default:
+               reflect = false;
+               next_state = cpuidle_find_deepest_state(drv, dev);
+       } else {
+               reflect = true;
                /*
-                * We can't use the cpuidle framework, let's use the default
-                * idle routine.
+                * Ask the cpuidle framework to choose a convenient idle state.
                 */
-               if (current_clr_polling_and_test())
-                       local_irq_enable();
-               else
-                       arch_cpu_idle();
-
-               goto exit_idle;
+               next_state = cpuidle_select(drv, dev);
        }
-
+       /* Fall back to the default arch idle method on errors. */
+       if (next_state < 0)
+               goto use_default;
 
        /*
         * The idle task must be scheduled, it is pointless to
@@ -183,7 +181,8 @@ use_default:
        /*
         * Give the governor an opportunity to reflect on the outcome
         */
-       cpuidle_reflect(dev, entered_state);
+       if (reflect)
+               cpuidle_reflect(dev, entered_state);
 
 exit_idle:
        __current_set_polling();
@@ -196,6 +195,19 @@ exit_idle:
 
        rcu_idle_exit();
        start_critical_timings();
+       return;
+
+use_default:
+       /*
+        * We can't use the cpuidle framework, let's use the default
+        * idle routine.
+        */
+       if (current_clr_polling_and_test())
+               local_irq_enable();
+       else
+               arch_cpu_idle();
+
+       goto exit_idle;
 }
 
 /*
index 667b2e6..a03d9cd 100644 (file)
@@ -1108,6 +1108,7 @@ DECLARE_RWSEM(uts_sem);
 /*
  * Work around broken programs that cannot handle "Linux 3.0".
  * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
+ * And we map 4.x to 2.6.60+x, so 4.0 would be 2.6.60.
  */
 static int override_release(char __user *release, size_t len)
 {
@@ -1127,7 +1128,7 @@ static int override_release(char __user *release, size_t len)
                                break;
                        rest++;
                }
-               v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
+               v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 60;
                copy = clamp_t(size_t, len, 1, sizeof(buf));
                copy = scnprintf(buf, copy, "2.6.%u%s", v, rest);
                ret = copy_to_user(release, buf, copy + 1);
index 88ea2d6..ce410bb 100644 (file)
@@ -1227,6 +1227,14 @@ static struct ctl_table vm_table[] = {
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
        },
+       {
+               .procname       = "dirtytime_expire_seconds",
+               .data           = &dirtytime_expire_interval,
+               .maxlen         = sizeof(dirty_expire_interval),
+               .mode           = 0644,
+               .proc_handler   = dirtytime_interval_handler,
+               .extra1         = &zero,
+       },
        {
                .procname       = "nr_pdflush_threads",
                .mode           = 0444 /* read-only */,
index eb682d5..6aac4be 100644 (file)
@@ -49,6 +49,7 @@ static void bc_set_mode(enum clock_event_mode mode,
  */
 static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
 {
+       int bc_moved;
        /*
         * We try to cancel the timer first. If the callback is on
         * flight on some other cpu then we let it handle it. If we
@@ -60,9 +61,15 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
         * restart the timer because we are in the callback, but we
         * can set the expiry time and let the callback return
         * HRTIMER_RESTART.
+        *
+        * Since we are in the idle loop at this point and because
+        * hrtimer_{start/cancel} functions call into tracing,
+        * calls to these functions must be bound within RCU_NONIDLE.
         */
-       if (hrtimer_try_to_cancel(&bctimer) >= 0) {
-               hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED);
+       RCU_NONIDLE(bc_moved = (hrtimer_try_to_cancel(&bctimer) >= 0) ?
+               !hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED) :
+                       0);
+       if (bc_moved) {
                /* Bind the "device" to the cpu */
                bc->bound_on = smp_processor_id();
        } else if (bc->bound_on == smp_processor_id()) {
index 45e5cb1..4f22802 100644 (file)
@@ -1059,6 +1059,12 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
 
 static struct pid * const ftrace_swapper_pid = &init_struct_pid;
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static int ftrace_graph_active;
+#else
+# define ftrace_graph_active 0
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 static struct ftrace_ops *removed_ops;
@@ -2041,8 +2047,12 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
                if (!ftrace_rec_count(rec))
                        rec->flags = 0;
                else
-                       /* Just disable the record (keep REGS state) */
-                       rec->flags &= ~FTRACE_FL_ENABLED;
+                       /*
+                        * Just disable the record, but keep the ops TRAMP
+                        * and REGS states. The _EN flags must be disabled though.
+                        */
+                       rec->flags &= ~(FTRACE_FL_ENABLED | FTRACE_FL_TRAMP_EN |
+                                       FTRACE_FL_REGS_EN);
        }
 
        return FTRACE_UPDATE_MAKE_NOP;
@@ -2688,24 +2698,36 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
 
 static void ftrace_startup_sysctl(void)
 {
+       int command;
+
        if (unlikely(ftrace_disabled))
                return;
 
        /* Force update next time */
        saved_ftrace_func = NULL;
        /* ftrace_start_up is true if we want ftrace running */
-       if (ftrace_start_up)
-               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+       if (ftrace_start_up) {
+               command = FTRACE_UPDATE_CALLS;
+               if (ftrace_graph_active)
+                       command |= FTRACE_START_FUNC_RET;
+               ftrace_startup_enable(command);
+       }
 }
 
 static void ftrace_shutdown_sysctl(void)
 {
+       int command;
+
        if (unlikely(ftrace_disabled))
                return;
 
        /* ftrace_start_up is true if ftrace is running */
-       if (ftrace_start_up)
-               ftrace_run_update_code(FTRACE_DISABLE_CALLS);
+       if (ftrace_start_up) {
+               command = FTRACE_DISABLE_CALLS;
+               if (ftrace_graph_active)
+                       command |= FTRACE_STOP_FUNC_RET;
+               ftrace_run_update_code(command);
+       }
 }
 
 static cycle_t         ftrace_update_time;
@@ -5558,12 +5580,12 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 
        if (ftrace_enabled) {
 
-               ftrace_startup_sysctl();
-
                /* we are starting ftrace again */
                if (ftrace_ops_list != &ftrace_list_end)
                        update_ftrace_function();
 
+               ftrace_startup_sysctl();
+
        } else {
                /* stopping ftrace calls (just send to ftrace_stub) */
                ftrace_trace_function = ftrace_stub;
@@ -5590,8 +5612,6 @@ static struct ftrace_ops graph_ops = {
        ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)
 };
 
-static int ftrace_graph_active;
-
 int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
 {
        return 0;
index f288493..41ff75b 100644 (file)
@@ -2728,19 +2728,57 @@ bool flush_work(struct work_struct *work)
 }
 EXPORT_SYMBOL_GPL(flush_work);
 
+struct cwt_wait {
+       wait_queue_t            wait;
+       struct work_struct      *work;
+};
+
+static int cwt_wakefn(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+       struct cwt_wait *cwait = container_of(wait, struct cwt_wait, wait);
+
+       if (cwait->work != key)
+               return 0;
+       return autoremove_wake_function(wait, mode, sync, key);
+}
+
 static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
 {
+       static DECLARE_WAIT_QUEUE_HEAD(cancel_waitq);
        unsigned long flags;
        int ret;
 
        do {
                ret = try_to_grab_pending(work, is_dwork, &flags);
                /*
-                * If someone else is canceling, wait for the same event it
-                * would be waiting for before retrying.
+                * If someone else is already canceling, wait for it to
+                * finish.  flush_work() doesn't work for PREEMPT_NONE
+                * because we may get scheduled between @work's completion
+                * and the other canceling task resuming and clearing
+                * CANCELING - flush_work() will return false immediately
+                * as @work is no longer busy, try_to_grab_pending() will
+                * return -ENOENT as @work is still being canceled and the
+                * other canceling task won't be able to clear CANCELING as
+                * we're hogging the CPU.
+                *
+                * Let's wait for completion using a waitqueue.  As this
+                * may lead to the thundering herd problem, use a custom
+                * wake function which matches @work along with exclusive
+                * wait and wakeup.
                 */
-               if (unlikely(ret == -ENOENT))
-                       flush_work(work);
+               if (unlikely(ret == -ENOENT)) {
+                       struct cwt_wait cwait;
+
+                       init_wait(&cwait.wait);
+                       cwait.wait.func = cwt_wakefn;
+                       cwait.work = work;
+
+                       prepare_to_wait_exclusive(&cancel_waitq, &cwait.wait,
+                                                 TASK_UNINTERRUPTIBLE);
+                       if (work_is_canceling(work))
+                               schedule();
+                       finish_wait(&cancel_waitq, &cwait.wait);
+               }
        } while (unlikely(ret < 0));
 
        /* tell other tasks trying to grab @work to back off */
@@ -2749,6 +2787,16 @@ static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
 
        flush_work(work);
        clear_work_data(work);
+
+       /*
+        * Paired with prepare_to_wait() above so that either
+        * waitqueue_active() is visible here or !work_is_canceling() is
+        * visible there.
+        */
+       smp_mb();
+       if (waitqueue_active(&cancel_waitq))
+               __wake_up(&cancel_waitq, TASK_NORMAL, 1, work);
+
        return ret;
 }
 
index 87eb3bf..58f74d2 100644 (file)
@@ -24,7 +24,7 @@ obj-y += lockref.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
-        gcd.o lcm.o list_sort.o uuid.o flex_array.o clz_ctz.o \
+        gcd.o lcm.o list_sort.o uuid.o flex_array.o iov_iter.o clz_ctz.o \
         bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
         percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o
 obj-y += string_helpers.o
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
new file mode 100644 (file)
index 0000000..9d96e28
--- /dev/null
@@ -0,0 +1,768 @@
+#include <linux/export.h>
+#include <linux/uio.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <net/checksum.h>
+
+#define iterate_iovec(i, n, __v, __p, skip, STEP) {    \
+       size_t left;                                    \
+       size_t wanted = n;                              \
+       __p = i->iov;                                   \
+       __v.iov_len = min(n, __p->iov_len - skip);      \
+       if (likely(__v.iov_len)) {                      \
+               __v.iov_base = __p->iov_base + skip;    \
+               left = (STEP);                          \
+               __v.iov_len -= left;                    \
+               skip += __v.iov_len;                    \
+               n -= __v.iov_len;                       \
+       } else {                                        \
+               left = 0;                               \
+       }                                               \
+       while (unlikely(!left && n)) {                  \
+               __p++;                                  \
+               __v.iov_len = min(n, __p->iov_len);     \
+               if (unlikely(!__v.iov_len))             \
+                       continue;                       \
+               __v.iov_base = __p->iov_base;           \
+               left = (STEP);                          \
+               __v.iov_len -= left;                    \
+               skip = __v.iov_len;                     \
+               n -= __v.iov_len;                       \
+       }                                               \
+       n = wanted - n;                                 \
+}
+
+#define iterate_kvec(i, n, __v, __p, skip, STEP) {     \
+       size_t wanted = n;                              \
+       __p = i->kvec;                                  \
+       __v.iov_len = min(n, __p->iov_len - skip);      \
+       if (likely(__v.iov_len)) {                      \
+               __v.iov_base = __p->iov_base + skip;    \
+               (void)(STEP);                           \
+               skip += __v.iov_len;                    \
+               n -= __v.iov_len;                       \
+       }                                               \
+       while (unlikely(n)) {                           \
+               __p++;                                  \
+               __v.iov_len = min(n, __p->iov_len);     \
+               if (unlikely(!__v.iov_len))             \
+                       continue;                       \
+               __v.iov_base = __p->iov_base;           \
+               (void)(STEP);                           \
+               skip = __v.iov_len;                     \
+               n -= __v.iov_len;                       \
+       }                                               \
+       n = wanted;                                     \
+}
+
+#define iterate_bvec(i, n, __v, __p, skip, STEP) {     \
+       size_t wanted = n;                              \
+       __p = i->bvec;                                  \
+       __v.bv_len = min_t(size_t, n, __p->bv_len - skip);      \
+       if (likely(__v.bv_len)) {                       \
+               __v.bv_page = __p->bv_page;             \
+               __v.bv_offset = __p->bv_offset + skip;  \
+               (void)(STEP);                           \
+               skip += __v.bv_len;                     \
+               n -= __v.bv_len;                        \
+       }                                               \
+       while (unlikely(n)) {                           \
+               __p++;                                  \
+               __v.bv_len = min_t(size_t, n, __p->bv_len);     \
+               if (unlikely(!__v.bv_len))              \
+                       continue;                       \
+               __v.bv_page = __p->bv_page;             \
+               __v.bv_offset = __p->bv_offset;         \
+               (void)(STEP);                           \
+               skip = __v.bv_len;                      \
+               n -= __v.bv_len;                        \
+       }                                               \
+       n = wanted;                                     \
+}
+
+#define iterate_all_kinds(i, n, v, I, B, K) {                  \
+       size_t skip = i->iov_offset;                            \
+       if (unlikely(i->type & ITER_BVEC)) {                    \
+               const struct bio_vec *bvec;                     \
+               struct bio_vec v;                               \
+               iterate_bvec(i, n, v, bvec, skip, (B))          \
+       } else if (unlikely(i->type & ITER_KVEC)) {             \
+               const struct kvec *kvec;                        \
+               struct kvec v;                                  \
+               iterate_kvec(i, n, v, kvec, skip, (K))          \
+       } else {                                                \
+               const struct iovec *iov;                        \
+               struct iovec v;                                 \
+               iterate_iovec(i, n, v, iov, skip, (I))          \
+       }                                                       \
+}
+
+#define iterate_and_advance(i, n, v, I, B, K) {                        \
+       size_t skip = i->iov_offset;                            \
+       if (unlikely(i->type & ITER_BVEC)) {                    \
+               const struct bio_vec *bvec;                     \
+               struct bio_vec v;                               \
+               iterate_bvec(i, n, v, bvec, skip, (B))          \
+               if (skip == bvec->bv_len) {                     \
+                       bvec++;                                 \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= bvec - i->bvec;                   \
+               i->bvec = bvec;                                 \
+       } else if (unlikely(i->type & ITER_KVEC)) {             \
+               const struct kvec *kvec;                        \
+               struct kvec v;                                  \
+               iterate_kvec(i, n, v, kvec, skip, (K))          \
+               if (skip == kvec->iov_len) {                    \
+                       kvec++;                                 \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= kvec - i->kvec;                   \
+               i->kvec = kvec;                                 \
+       } else {                                                \
+               const struct iovec *iov;                        \
+               struct iovec v;                                 \
+               iterate_iovec(i, n, v, iov, skip, (I))          \
+               if (skip == iov->iov_len) {                     \
+                       iov++;                                  \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= iov - i->iov;                     \
+               i->iov = iov;                                   \
+       }                                                       \
+       i->count -= n;                                          \
+       i->iov_offset = skip;                                   \
+}
+
+static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+       void *kaddr, *from;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       if (!fault_in_pages_writeable(buf, copy)) {
+               kaddr = kmap_atomic(page);
+               from = kaddr + offset;
+
+               /* first chunk, usually the only one */
+               left = __copy_to_user_inatomic(buf, from, copy);
+               copy -= left;
+               skip += copy;
+               from += copy;
+               bytes -= copy;
+
+               while (unlikely(!left && bytes)) {
+                       iov++;
+                       buf = iov->iov_base;
+                       copy = min(bytes, iov->iov_len);
+                       left = __copy_to_user_inatomic(buf, from, copy);
+                       copy -= left;
+                       skip = copy;
+                       from += copy;
+                       bytes -= copy;
+               }
+               if (likely(!bytes)) {
+                       kunmap_atomic(kaddr);
+                       goto done;
+               }
+               offset = from - kaddr;
+               buf += copy;
+               kunmap_atomic(kaddr);
+               copy = min(bytes, iov->iov_len - skip);
+       }
+       /* Too bad - revert to non-atomic kmap */
+       kaddr = kmap(page);
+       from = kaddr + offset;
+       left = __copy_to_user(buf, from, copy);
+       copy -= left;
+       skip += copy;
+       from += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_to_user(buf, from, copy);
+               copy -= left;
+               skip = copy;
+               from += copy;
+               bytes -= copy;
+       }
+       kunmap(page);
+done:
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+       void *kaddr, *to;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       if (!fault_in_pages_readable(buf, copy)) {
+               kaddr = kmap_atomic(page);
+               to = kaddr + offset;
+
+               /* first chunk, usually the only one */
+               left = __copy_from_user_inatomic(to, buf, copy);
+               copy -= left;
+               skip += copy;
+               to += copy;
+               bytes -= copy;
+
+               while (unlikely(!left && bytes)) {
+                       iov++;
+                       buf = iov->iov_base;
+                       copy = min(bytes, iov->iov_len);
+                       left = __copy_from_user_inatomic(to, buf, copy);
+                       copy -= left;
+                       skip = copy;
+                       to += copy;
+                       bytes -= copy;
+               }
+               if (likely(!bytes)) {
+                       kunmap_atomic(kaddr);
+                       goto done;
+               }
+               offset = to - kaddr;
+               buf += copy;
+               kunmap_atomic(kaddr);
+               copy = min(bytes, iov->iov_len - skip);
+       }
+       /* Too bad - revert to non-atomic kmap */
+       kaddr = kmap(page);
+       to = kaddr + offset;
+       left = __copy_from_user(to, buf, copy);
+       copy -= left;
+       skip += copy;
+       to += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_from_user(to, buf, copy);
+               copy -= left;
+               skip = copy;
+               to += copy;
+               bytes -= copy;
+       }
+       kunmap(page);
+done:
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+/*
+ * Fault in the first iovec of the given iov_iter, to a maximum length
+ * of bytes. Returns 0 on success, or non-zero if the memory could not be
+ * accessed (ie. because it is an invalid address).
+ *
+ * writev-intensive code may want this to prefault several iovecs -- that
+ * would be possible (callers must not rely on the fact that _only_ the
+ * first iovec will be faulted with the current implementation).
+ */
+int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
+{
+       if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
+               char __user *buf = i->iov->iov_base + i->iov_offset;
+               bytes = min(bytes, i->iov->iov_len - i->iov_offset);
+               return fault_in_pages_readable(buf, bytes);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_fault_in_readable);
+
+void iov_iter_init(struct iov_iter *i, int direction,
+                       const struct iovec *iov, unsigned long nr_segs,
+                       size_t count)
+{
+       /* It will get better.  Eventually... */
+       if (segment_eq(get_fs(), KERNEL_DS)) {
+               direction |= ITER_KVEC;
+               i->type = direction;
+               i->kvec = (struct kvec *)iov;
+       } else {
+               i->type = direction;
+               i->iov = iov;
+       }
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_init);
+
+static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
+{
+       char *from = kmap_atomic(page);
+       memcpy(to, from + offset, len);
+       kunmap_atomic(from);
+}
+
+static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len)
+{
+       char *to = kmap_atomic(page);
+       memcpy(to + offset, from, len);
+       kunmap_atomic(to);
+}
+
+static void memzero_page(struct page *page, size_t offset, size_t len)
+{
+       char *addr = kmap_atomic(page);
+       memset(addr + offset, 0, len);
+       kunmap_atomic(addr);
+}
+
+size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *from = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len,
+                              v.iov_len),
+               memcpy_to_page(v.bv_page, v.bv_offset,
+                              (from += v.bv_len) - v.bv_len, v.bv_len),
+               memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_to_iter);
+
+size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *to = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base,
+                                v.iov_len),
+               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_from_iter);
+
+size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *to = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_from_user_nocache((to += v.iov_len) - v.iov_len,
+                                        v.iov_base, v.iov_len),
+               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_from_iter_nocache);
+
+size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       if (i->type & (ITER_BVEC|ITER_KVEC)) {
+               void *kaddr = kmap_atomic(page);
+               size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
+               kunmap_atomic(kaddr);
+               return wanted;
+       } else
+               return copy_page_to_iter_iovec(page, offset, bytes, i);
+}
+EXPORT_SYMBOL(copy_page_to_iter);
+
+size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       if (i->type & (ITER_BVEC|ITER_KVEC)) {
+               void *kaddr = kmap_atomic(page);
+               size_t wanted = copy_from_iter(kaddr + offset, bytes, i);
+               kunmap_atomic(kaddr);
+               return wanted;
+       } else
+               return copy_page_from_iter_iovec(page, offset, bytes, i);
+}
+EXPORT_SYMBOL(copy_page_from_iter);
+
+size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
+{
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __clear_user(v.iov_base, v.iov_len),
+               memzero_page(v.bv_page, v.bv_offset, v.bv_len),
+               memset(v.iov_base, 0, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(iov_iter_zero);
+
+size_t iov_iter_copy_from_user_atomic(struct page *page,
+               struct iov_iter *i, unsigned long offset, size_t bytes)
+{
+       char *kaddr = kmap_atomic(page), *p = kaddr + offset;
+       iterate_all_kinds(i, bytes, v,
+               __copy_from_user_inatomic((p += v.iov_len) - v.iov_len,
+                                         v.iov_base, v.iov_len),
+               memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+       kunmap_atomic(kaddr);
+       return bytes;
+}
+EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
+
+void iov_iter_advance(struct iov_iter *i, size_t size)
+{
+       iterate_and_advance(i, size, v, 0, 0, 0)
+}
+EXPORT_SYMBOL(iov_iter_advance);
+
+/*
+ * Return the count of just the current iov_iter segment.
+ */
+size_t iov_iter_single_seg_count(const struct iov_iter *i)
+{
+       if (i->nr_segs == 1)
+               return i->count;
+       else if (i->type & ITER_BVEC)
+               return min(i->count, i->bvec->bv_len - i->iov_offset);
+       else
+               return min(i->count, i->iov->iov_len - i->iov_offset);
+}
+EXPORT_SYMBOL(iov_iter_single_seg_count);
+
+void iov_iter_kvec(struct iov_iter *i, int direction,
+                       const struct kvec *kvec, unsigned long nr_segs,
+                       size_t count)
+{
+       BUG_ON(!(direction & ITER_KVEC));
+       i->type = direction;
+       i->kvec = kvec;
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_kvec);
+
+void iov_iter_bvec(struct iov_iter *i, int direction,
+                       const struct bio_vec *bvec, unsigned long nr_segs,
+                       size_t count)
+{
+       BUG_ON(!(direction & ITER_BVEC));
+       i->type = direction;
+       i->bvec = bvec;
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_bvec);
+
+unsigned long iov_iter_alignment(const struct iov_iter *i)
+{
+       unsigned long res = 0;
+       size_t size = i->count;
+
+       if (!size)
+               return 0;
+
+       iterate_all_kinds(i, size, v,
+               (res |= (unsigned long)v.iov_base | v.iov_len, 0),
+               res |= v.bv_offset | v.bv_len,
+               res |= (unsigned long)v.iov_base | v.iov_len
+       )
+       return res;
+}
+EXPORT_SYMBOL(iov_iter_alignment);
+
+ssize_t iov_iter_get_pages(struct iov_iter *i,
+                  struct page **pages, size_t maxsize, unsigned maxpages,
+                  size_t *start)
+{
+       if (maxsize > i->count)
+               maxsize = i->count;
+
+       if (!maxsize)
+               return 0;
+
+       iterate_all_kinds(i, maxsize, v, ({
+               unsigned long addr = (unsigned long)v.iov_base;
+               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
+               int n;
+               int res;
+
+               if (len > maxpages * PAGE_SIZE)
+                       len = maxpages * PAGE_SIZE;
+               addr &= ~(PAGE_SIZE - 1);
+               n = DIV_ROUND_UP(len, PAGE_SIZE);
+               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
+               if (unlikely(res < 0))
+                       return res;
+               return (res == n ? len : res * PAGE_SIZE) - *start;
+       0;}),({
+               /* can't be more than PAGE_SIZE */
+               *start = v.bv_offset;
+               get_page(*pages = v.bv_page);
+               return v.bv_len;
+       }),({
+               return -EFAULT;
+       })
+       )
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_get_pages);
+
+static struct page **get_pages_array(size_t n)
+{
+       struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
+       if (!p)
+               p = vmalloc(n * sizeof(struct page *));
+       return p;
+}
+
+ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
+                  struct page ***pages, size_t maxsize,
+                  size_t *start)
+{
+       struct page **p;
+
+       if (maxsize > i->count)
+               maxsize = i->count;
+
+       if (!maxsize)
+               return 0;
+
+       iterate_all_kinds(i, maxsize, v, ({
+               unsigned long addr = (unsigned long)v.iov_base;
+               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
+               int n;
+               int res;
+
+               addr &= ~(PAGE_SIZE - 1);
+               n = DIV_ROUND_UP(len, PAGE_SIZE);
+               p = get_pages_array(n);
+               if (!p)
+                       return -ENOMEM;
+               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
+               if (unlikely(res < 0)) {
+                       kvfree(p);
+                       return res;
+               }
+               *pages = p;
+               return (res == n ? len : res * PAGE_SIZE) - *start;
+       0;}),({
+               /* can't be more than PAGE_SIZE */
+               *start = v.bv_offset;
+               *pages = p = get_pages_array(1);
+               if (!p)
+                       return -ENOMEM;
+               get_page(*p = v.bv_page);
+               return v.bv_len;
+       }),({
+               return -EFAULT;
+       })
+       )
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_get_pages_alloc);
+
+size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
+                              struct iov_iter *i)
+{
+       char *to = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       sum = *csum;
+       iterate_and_advance(i, bytes, v, ({
+               int err = 0;
+               next = csum_and_copy_from_user(v.iov_base, 
+                                              (to += v.iov_len) - v.iov_len,
+                                              v.iov_len, 0, &err);
+               if (!err) {
+                       sum = csum_block_add(sum, next, off);
+                       off += v.iov_len;
+               }
+               err ? v.iov_len : 0;
+       }), ({
+               char *p = kmap_atomic(v.bv_page);
+               next = csum_partial_copy_nocheck(p + v.bv_offset,
+                                                (to += v.bv_len) - v.bv_len,
+                                                v.bv_len, 0);
+               kunmap_atomic(p);
+               sum = csum_block_add(sum, next, off);
+               off += v.bv_len;
+       }),({
+               next = csum_partial_copy_nocheck(v.iov_base,
+                                                (to += v.iov_len) - v.iov_len,
+                                                v.iov_len, 0);
+               sum = csum_block_add(sum, next, off);
+               off += v.iov_len;
+       })
+       )
+       *csum = sum;
+       return bytes;
+}
+EXPORT_SYMBOL(csum_and_copy_from_iter);
+
+size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
+                            struct iov_iter *i)
+{
+       char *from = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       sum = *csum;
+       iterate_and_advance(i, bytes, v, ({
+               int err = 0;
+               next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
+                                            v.iov_base, 
+                                            v.iov_len, 0, &err);
+               if (!err) {
+                       sum = csum_block_add(sum, next, off);
+                       off += v.iov_len;
+               }
+               err ? v.iov_len : 0;
+       }), ({
+               char *p = kmap_atomic(v.bv_page);
+               next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len,
+                                                p + v.bv_offset,
+                                                v.bv_len, 0);
+               kunmap_atomic(p);
+               sum = csum_block_add(sum, next, off);
+               off += v.bv_len;
+       }),({
+               next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len,
+                                                v.iov_base,
+                                                v.iov_len, 0);
+               sum = csum_block_add(sum, next, off);
+               off += v.iov_len;
+       })
+       )
+       *csum = sum;
+       return bytes;
+}
+EXPORT_SYMBOL(csum_and_copy_to_iter);
+
+int iov_iter_npages(const struct iov_iter *i, int maxpages)
+{
+       size_t size = i->count;
+       int npages = 0;
+
+       if (!size)
+               return 0;
+
+       iterate_all_kinds(i, size, v, ({
+               unsigned long p = (unsigned long)v.iov_base;
+               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
+                       - p / PAGE_SIZE;
+               if (npages >= maxpages)
+                       return maxpages;
+       0;}),({
+               npages++;
+               if (npages >= maxpages)
+                       return maxpages;
+       }),({
+               unsigned long p = (unsigned long)v.iov_base;
+               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
+                       - p / PAGE_SIZE;
+               if (npages >= maxpages)
+                       return maxpages;
+       })
+       )
+       return npages;
+}
+EXPORT_SYMBOL(iov_iter_npages);
+
+const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
+{
+       *new = *old;
+       if (new->type & ITER_BVEC)
+               return new->bvec = kmemdup(new->bvec,
+                                   new->nr_segs * sizeof(struct bio_vec),
+                                   flags);
+       else
+               /* iovec and kvec have identical layout */
+               return new->iov = kmemdup(new->iov,
+                                  new->nr_segs * sizeof(struct iovec),
+                                  flags);
+}
+EXPORT_SYMBOL(dup_iter);
index e97dbd5..03d7fcb 100644 (file)
--- a/lib/lcm.c
+++ b/lib/lcm.c
@@ -12,3 +12,14 @@ unsigned long lcm(unsigned long a, unsigned long b)
                return 0;
 }
 EXPORT_SYMBOL_GPL(lcm);
+
+unsigned long lcm_not_zero(unsigned long a, unsigned long b)
+{
+       unsigned long l = lcm(a, b);
+
+       if (l)
+               return l;
+
+       return (b ? : a);
+}
+EXPORT_SYMBOL_GPL(lcm_not_zero);
index 7a85967..f0f5c5c 100644 (file)
@@ -139,6 +139,9 @@ static int lz4_uncompress(const char *source, char *dest, int osize)
                        /* Error: request to write beyond destination buffer */
                        if (cpy > oend)
                                goto _output_error;
+                       if ((ref + COPYLENGTH) > oend ||
+                                       (op + COPYLENGTH) > oend)
+                               goto _output_error;
                        LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
                        while (op < cpy)
                                *op++ = *ref++;
index 76a1b59..f5907d2 100644 (file)
@@ -279,6 +279,8 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count)
        int minlen = min_t(int, count, nla_len(src));
 
        memcpy(dest, nla_data(src), minlen);
+       if (count > minlen)
+               memset(dest + minlen, 0, count - minlen);
 
        return minlen;
 }
index 9cc4c4a..b5344ef 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/log2.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
@@ -217,15 +218,15 @@ static void bucket_table_free(const struct bucket_table *tbl)
 static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
                                               size_t nbuckets)
 {
-       struct bucket_table *tbl;
+       struct bucket_table *tbl = NULL;
        size_t size;
        int i;
 
        size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]);
-       tbl = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+       if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
+               tbl = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
        if (tbl == NULL)
                tbl = vzalloc(size);
-
        if (tbl == NULL)
                return NULL;
 
@@ -247,26 +248,24 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
  * @ht:                hash table
  * @new_size:  new table size
  */
-bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size)
+static bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size)
 {
        /* Expand table when exceeding 75% load */
        return atomic_read(&ht->nelems) > (new_size / 4 * 3) &&
-              (ht->p.max_shift && atomic_read(&ht->shift) < ht->p.max_shift);
+              (!ht->p.max_shift || atomic_read(&ht->shift) < ht->p.max_shift);
 }
-EXPORT_SYMBOL_GPL(rht_grow_above_75);
 
 /**
  * rht_shrink_below_30 - returns true if nelems < 0.3 * table-size
  * @ht:                hash table
  * @new_size:  new table size
  */
-bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size)
+static bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size)
 {
        /* Shrink table beneath 30% load */
        return atomic_read(&ht->nelems) < (new_size * 3 / 10) &&
               (atomic_read(&ht->shift) > ht->p.min_shift);
 }
-EXPORT_SYMBOL_GPL(rht_shrink_below_30);
 
 static void lock_buckets(struct bucket_table *new_tbl,
                         struct bucket_table *old_tbl, unsigned int hash)
@@ -414,6 +413,7 @@ int rhashtable_expand(struct rhashtable *ht)
                        }
                }
                unlock_buckets(new_tbl, old_tbl, new_hash);
+               cond_resched();
        }
 
        /* Unzip interleaved hash chains */
@@ -437,6 +437,7 @@ int rhashtable_expand(struct rhashtable *ht)
                                complete = false;
 
                        unlock_buckets(new_tbl, old_tbl, old_hash);
+                       cond_resched();
                }
        }
 
@@ -495,6 +496,7 @@ int rhashtable_shrink(struct rhashtable *ht)
                                   tbl->buckets[new_hash + new_tbl->size]);
 
                unlock_buckets(new_tbl, tbl, new_hash);
+               cond_resched();
        }
 
        /* Publish the new, valid hash table */
@@ -528,31 +530,19 @@ static void rht_deferred_worker(struct work_struct *work)
        list_for_each_entry(walker, &ht->walkers, list)
                walker->resize = true;
 
-       if (ht->p.grow_decision && ht->p.grow_decision(ht, tbl->size))
+       if (rht_grow_above_75(ht, tbl->size))
                rhashtable_expand(ht);
-       else if (ht->p.shrink_decision && ht->p.shrink_decision(ht, tbl->size))
+       else if (rht_shrink_below_30(ht, tbl->size))
                rhashtable_shrink(ht);
-
 unlock:
        mutex_unlock(&ht->mutex);
 }
 
-static void rhashtable_wakeup_worker(struct rhashtable *ht)
-{
-       struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht);
-       struct bucket_table *new_tbl = rht_dereference_rcu(ht->future_tbl, ht);
-       size_t size = tbl->size;
-
-       /* Only adjust the table if no resizing is currently in progress. */
-       if (tbl == new_tbl &&
-           ((ht->p.grow_decision && ht->p.grow_decision(ht, size)) ||
-            (ht->p.shrink_decision && ht->p.shrink_decision(ht, size))))
-               schedule_work(&ht->run_work);
-}
-
 static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
-                               struct bucket_table *tbl, u32 hash)
+                               struct bucket_table *tbl,
+                               const struct bucket_table *old_tbl, u32 hash)
 {
+       bool no_resize_running = tbl == old_tbl;
        struct rhash_head *head;
 
        hash = rht_bucket_index(tbl, hash);
@@ -568,8 +558,8 @@ static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
        rcu_assign_pointer(tbl->buckets[hash], obj);
 
        atomic_inc(&ht->nelems);
-
-       rhashtable_wakeup_worker(ht);
+       if (no_resize_running && rht_grow_above_75(ht, tbl->size))
+               schedule_work(&ht->run_work);
 }
 
 /**
@@ -599,7 +589,7 @@ void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj)
        hash = obj_raw_hashfn(ht, rht_obj(ht, obj));
 
        lock_buckets(tbl, old_tbl, hash);
-       __rhashtable_insert(ht, obj, tbl, hash);
+       __rhashtable_insert(ht, obj, tbl, old_tbl, hash);
        unlock_buckets(tbl, old_tbl, hash);
 
        rcu_read_unlock();
@@ -681,8 +671,11 @@ found:
        unlock_buckets(new_tbl, old_tbl, new_hash);
 
        if (ret) {
+               bool no_resize_running = new_tbl == old_tbl;
+
                atomic_dec(&ht->nelems);
-               rhashtable_wakeup_worker(ht);
+               if (no_resize_running && rht_shrink_below_30(ht, new_tbl->size))
+                       schedule_work(&ht->run_work);
        }
 
        rcu_read_unlock();
@@ -852,7 +845,7 @@ bool rhashtable_lookup_compare_insert(struct rhashtable *ht,
                goto exit;
        }
 
-       __rhashtable_insert(ht, obj, new_tbl, new_hash);
+       __rhashtable_insert(ht, obj, new_tbl, old_tbl, new_hash);
 
 exit:
        unlock_buckets(new_tbl, old_tbl, new_hash);
@@ -894,6 +887,9 @@ int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter)
        if (!iter->walker)
                return -ENOMEM;
 
+       INIT_LIST_HEAD(&iter->walker->list);
+       iter->walker->resize = false;
+
        mutex_lock(&ht->mutex);
        list_add(&iter->walker->list, &ht->walkers);
        mutex_unlock(&ht->mutex);
@@ -1111,8 +1107,7 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params)
        if (!ht->p.hash_rnd)
                get_random_bytes(&ht->p.hash_rnd, sizeof(ht->p.hash_rnd));
 
-       if (ht->p.grow_decision || ht->p.shrink_decision)
-               INIT_WORK(&ht->run_work, rht_deferred_worker);
+       INIT_WORK(&ht->run_work, rht_deferred_worker);
 
        return 0;
 }
@@ -1130,8 +1125,7 @@ void rhashtable_destroy(struct rhashtable *ht)
 {
        ht->being_destroyed = true;
 
-       if (ht->p.grow_decision || ht->p.shrink_decision)
-               cancel_work_sync(&ht->run_work);
+       cancel_work_sync(&ht->run_work);
 
        mutex_lock(&ht->mutex);
        bucket_table_free(rht_dereference(ht->tbl, ht));
index 88c0854..5c94e10 100644 (file)
@@ -61,7 +61,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
 
        if (s->len < s->size) {
                len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
-               if (seq_buf_can_fit(s, len)) {
+               if (s->len + len < s->size) {
                        s->len += len;
                        return 0;
                }
@@ -118,7 +118,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
 
        if (s->len < s->size) {
                ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
-               if (seq_buf_can_fit(s, ret)) {
+               if (s->len + ret < s->size) {
                        s->len += ret;
                        return 0;
                }
index 1dfeba7..67c7593 100644 (file)
@@ -191,18 +191,18 @@ error:
        return err;
 }
 
+static struct rhashtable ht;
+
 static int __init test_rht_init(void)
 {
-       struct rhashtable ht;
        struct rhashtable_params params = {
                .nelem_hint = TEST_HT_SIZE,
                .head_offset = offsetof(struct test_obj, node),
                .key_offset = offsetof(struct test_obj, value),
                .key_len = sizeof(int),
                .hashfn = jhash,
+               .max_shift = 1, /* we expand/shrink manually here */
                .nulls_base = (3U << RHT_BASE_SHIFT),
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
        int err;
 
@@ -222,6 +222,11 @@ static int __init test_rht_init(void)
        return err;
 }
 
+static void __exit test_rht_exit(void)
+{
+}
+
 module_init(test_rht_init);
+module_exit(test_rht_exit);
 
 MODULE_LICENSE("GPL v2");
index 3c1caa2..15dbe99 100644 (file)
@@ -21,7 +21,7 @@ obj-y                 := filemap.o mempool.o oom_kill.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
                           compaction.o vmacache.o \
                           interval_tree.o list_lru.o workingset.o \
-                          iov_iter.o debug.o $(mmu-y)
+                          debug.o $(mmu-y)
 
 obj-y += init-mm.o
 
index 75016fd..68ecb7a 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -64,15 +64,17 @@ static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
        return (1UL << (align_order - cma->order_per_bit)) - 1;
 }
 
+/*
+ * Find a PFN aligned to the specified order and return an offset represented in
+ * order_per_bits.
+ */
 static unsigned long cma_bitmap_aligned_offset(struct cma *cma, int align_order)
 {
-       unsigned int alignment;
-
        if (align_order <= cma->order_per_bit)
                return 0;
-       alignment = 1UL << (align_order - cma->order_per_bit);
-       return ALIGN(cma->base_pfn, alignment) -
-               (cma->base_pfn >> cma->order_per_bit);
+
+       return (ALIGN(cma->base_pfn, (1UL << align_order))
+               - cma->base_pfn) >> cma->order_per_bit;
 }
 
 static unsigned long cma_bitmap_maxno(struct cma *cma)
index fc00c8c..6817b03 100644 (file)
@@ -1260,6 +1260,7 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        int target_nid, last_cpupid = -1;
        bool page_locked;
        bool migrated = false;
+       bool was_writable;
        int flags = 0;
 
        /* A PROT_NONE fault should not end up here */
@@ -1291,12 +1292,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                flags |= TNF_FAULT_LOCAL;
        }
 
-       /*
-        * Avoid grouping on DSO/COW pages in specific and RO pages
-        * in general, RO pages shouldn't hurt as much anyway since
-        * they can be in shared cache state.
-        */
-       if (!pmd_write(pmd))
+       /* See similar comment in do_numa_page for explanation */
+       if (!(vma->vm_flags & VM_WRITE))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -1353,12 +1350,17 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (migrated) {
                flags |= TNF_MIGRATED;
                page_nid = target_nid;
-       }
+       } else
+               flags |= TNF_MIGRATE_FAIL;
 
        goto out;
 clear_pmdnuma:
        BUG_ON(!PageLocked(page));
+       was_writable = pmd_write(pmd);
        pmd = pmd_modify(pmd, vma->vm_page_prot);
+       pmd = pmd_mkyoung(pmd);
+       if (was_writable)
+               pmd = pmd_mkwrite(pmd);
        set_pmd_at(mm, haddr, pmdp, pmd);
        update_mmu_cache_pmd(vma, addr, pmdp);
        unlock_page(page);
@@ -1482,6 +1484,8 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
 
        if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
                pmd_t entry;
+               bool preserve_write = prot_numa && pmd_write(*pmd);
+               ret = 1;
 
                /*
                 * Avoid trapping faults against the zero page. The read-only
@@ -1490,16 +1494,17 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                 */
                if (prot_numa && is_huge_zero_pmd(*pmd)) {
                        spin_unlock(ptl);
-                       return 0;
+                       return ret;
                }
 
                if (!prot_numa || !pmd_protnone(*pmd)) {
-                       ret = 1;
                        entry = pmdp_get_and_clear_notify(mm, addr, pmd);
                        entry = pmd_modify(entry, newprot);
+                       if (preserve_write)
+                               entry = pmd_mkwrite(entry);
                        ret = HPAGE_PMD_NR;
                        set_pmd_at(mm, addr, pmd, entry);
-                       BUG_ON(pmd_write(entry));
+                       BUG_ON(!preserve_write && pmd_write(entry));
                }
                spin_unlock(ptl);
        }
index 0a9ac6c..c41b2a0 100644 (file)
@@ -917,7 +917,6 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
        __SetPageHead(page);
        __ClearPageReserved(page);
        for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
-               __SetPageTail(p);
                /*
                 * For gigantic hugepages allocated through bootmem at
                 * boot, it's safer to be consistent with the not-gigantic
@@ -933,6 +932,9 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
                __ClearPageReserved(p);
                set_page_count(p, 0);
                p->first_page = page;
+               /* Make sure p->first_page is always valid for PageTail() */
+               smp_wmb();
+               __SetPageTail(p);
        }
 }
 
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
deleted file mode 100644 (file)
index 8277320..0000000
+++ /dev/null
@@ -1,753 +0,0 @@
-#include <linux/export.h>
-#include <linux/uio.h>
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <net/checksum.h>
-
-#define iterate_iovec(i, n, __v, __p, skip, STEP) {    \
-       size_t left;                                    \
-       size_t wanted = n;                              \
-       __p = i->iov;                                   \
-       __v.iov_len = min(n, __p->iov_len - skip);      \
-       if (likely(__v.iov_len)) {                      \
-               __v.iov_base = __p->iov_base + skip;    \
-               left = (STEP);                          \
-               __v.iov_len -= left;                    \
-               skip += __v.iov_len;                    \
-               n -= __v.iov_len;                       \
-       } else {                                        \
-               left = 0;                               \
-       }                                               \
-       while (unlikely(!left && n)) {                  \
-               __p++;                                  \
-               __v.iov_len = min(n, __p->iov_len);     \
-               if (unlikely(!__v.iov_len))             \
-                       continue;                       \
-               __v.iov_base = __p->iov_base;           \
-               left = (STEP);                          \
-               __v.iov_len -= left;                    \
-               skip = __v.iov_len;                     \
-               n -= __v.iov_len;                       \
-       }                                               \
-       n = wanted - n;                                 \
-}
-
-#define iterate_kvec(i, n, __v, __p, skip, STEP) {     \
-       size_t wanted = n;                              \
-       __p = i->kvec;                                  \
-       __v.iov_len = min(n, __p->iov_len - skip);      \
-       if (likely(__v.iov_len)) {                      \
-               __v.iov_base = __p->iov_base + skip;    \
-               (void)(STEP);                           \
-               skip += __v.iov_len;                    \
-               n -= __v.iov_len;                       \
-       }                                               \
-       while (unlikely(n)) {                           \
-               __p++;                                  \
-               __v.iov_len = min(n, __p->iov_len);     \
-               if (unlikely(!__v.iov_len))             \
-                       continue;                       \
-               __v.iov_base = __p->iov_base;           \
-               (void)(STEP);                           \
-               skip = __v.iov_len;                     \
-               n -= __v.iov_len;                       \
-       }                                               \
-       n = wanted;                                     \
-}
-
-#define iterate_bvec(i, n, __v, __p, skip, STEP) {     \
-       size_t wanted = n;                              \
-       __p = i->bvec;                                  \
-       __v.bv_len = min_t(size_t, n, __p->bv_len - skip);      \
-       if (likely(__v.bv_len)) {                       \
-               __v.bv_page = __p->bv_page;             \
-               __v.bv_offset = __p->bv_offset + skip;  \
-               (void)(STEP);                           \
-               skip += __v.bv_len;                     \
-               n -= __v.bv_len;                        \
-       }                                               \
-       while (unlikely(n)) {                           \
-               __p++;                                  \
-               __v.bv_len = min_t(size_t, n, __p->bv_len);     \
-               if (unlikely(!__v.bv_len))              \
-                       continue;                       \
-               __v.bv_page = __p->bv_page;             \
-               __v.bv_offset = __p->bv_offset;         \
-               (void)(STEP);                           \
-               skip = __v.bv_len;                      \
-               n -= __v.bv_len;                        \
-       }                                               \
-       n = wanted;                                     \
-}
-
-#define iterate_all_kinds(i, n, v, I, B, K) {                  \
-       size_t skip = i->iov_offset;                            \
-       if (unlikely(i->type & ITER_BVEC)) {                    \
-               const struct bio_vec *bvec;                     \
-               struct bio_vec v;                               \
-               iterate_bvec(i, n, v, bvec, skip, (B))          \
-       } else if (unlikely(i->type & ITER_KVEC)) {             \
-               const struct kvec *kvec;                        \
-               struct kvec v;                                  \
-               iterate_kvec(i, n, v, kvec, skip, (K))          \
-       } else {                                                \
-               const struct iovec *iov;                        \
-               struct iovec v;                                 \
-               iterate_iovec(i, n, v, iov, skip, (I))          \
-       }                                                       \
-}
-
-#define iterate_and_advance(i, n, v, I, B, K) {                        \
-       size_t skip = i->iov_offset;                            \
-       if (unlikely(i->type & ITER_BVEC)) {                    \
-               const struct bio_vec *bvec;                     \
-               struct bio_vec v;                               \
-               iterate_bvec(i, n, v, bvec, skip, (B))          \
-               if (skip == bvec->bv_len) {                     \
-                       bvec++;                                 \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= bvec - i->bvec;                   \
-               i->bvec = bvec;                                 \
-       } else if (unlikely(i->type & ITER_KVEC)) {             \
-               const struct kvec *kvec;                        \
-               struct kvec v;                                  \
-               iterate_kvec(i, n, v, kvec, skip, (K))          \
-               if (skip == kvec->iov_len) {                    \
-                       kvec++;                                 \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= kvec - i->kvec;                   \
-               i->kvec = kvec;                                 \
-       } else {                                                \
-               const struct iovec *iov;                        \
-               struct iovec v;                                 \
-               iterate_iovec(i, n, v, iov, skip, (I))          \
-               if (skip == iov->iov_len) {                     \
-                       iov++;                                  \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= iov - i->iov;                     \
-               i->iov = iov;                                   \
-       }                                                       \
-       i->count -= n;                                          \
-       i->iov_offset = skip;                                   \
-}
-
-static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-       void *kaddr, *from;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       if (!fault_in_pages_writeable(buf, copy)) {
-               kaddr = kmap_atomic(page);
-               from = kaddr + offset;
-
-               /* first chunk, usually the only one */
-               left = __copy_to_user_inatomic(buf, from, copy);
-               copy -= left;
-               skip += copy;
-               from += copy;
-               bytes -= copy;
-
-               while (unlikely(!left && bytes)) {
-                       iov++;
-                       buf = iov->iov_base;
-                       copy = min(bytes, iov->iov_len);
-                       left = __copy_to_user_inatomic(buf, from, copy);
-                       copy -= left;
-                       skip = copy;
-                       from += copy;
-                       bytes -= copy;
-               }
-               if (likely(!bytes)) {
-                       kunmap_atomic(kaddr);
-                       goto done;
-               }
-               offset = from - kaddr;
-               buf += copy;
-               kunmap_atomic(kaddr);
-               copy = min(bytes, iov->iov_len - skip);
-       }
-       /* Too bad - revert to non-atomic kmap */
-       kaddr = kmap(page);
-       from = kaddr + offset;
-       left = __copy_to_user(buf, from, copy);
-       copy -= left;
-       skip += copy;
-       from += copy;
-       bytes -= copy;
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __copy_to_user(buf, from, copy);
-               copy -= left;
-               skip = copy;
-               from += copy;
-               bytes -= copy;
-       }
-       kunmap(page);
-done:
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
-
-static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-       void *kaddr, *to;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       if (!fault_in_pages_readable(buf, copy)) {
-               kaddr = kmap_atomic(page);
-               to = kaddr + offset;
-
-               /* first chunk, usually the only one */
-               left = __copy_from_user_inatomic(to, buf, copy);
-               copy -= left;
-               skip += copy;
-               to += copy;
-               bytes -= copy;
-
-               while (unlikely(!left && bytes)) {
-                       iov++;
-                       buf = iov->iov_base;
-                       copy = min(bytes, iov->iov_len);
-                       left = __copy_from_user_inatomic(to, buf, copy);
-                       copy -= left;
-                       skip = copy;
-                       to += copy;
-                       bytes -= copy;
-               }
-               if (likely(!bytes)) {
-                       kunmap_atomic(kaddr);
-                       goto done;
-               }
-               offset = to - kaddr;
-               buf += copy;
-               kunmap_atomic(kaddr);
-               copy = min(bytes, iov->iov_len - skip);
-       }
-       /* Too bad - revert to non-atomic kmap */
-       kaddr = kmap(page);
-       to = kaddr + offset;
-       left = __copy_from_user(to, buf, copy);
-       copy -= left;
-       skip += copy;
-       to += copy;
-       bytes -= copy;
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __copy_from_user(to, buf, copy);
-               copy -= left;
-               skip = copy;
-               to += copy;
-               bytes -= copy;
-       }
-       kunmap(page);
-done:
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
-
-/*
- * Fault in the first iovec of the given iov_iter, to a maximum length
- * of bytes. Returns 0 on success, or non-zero if the memory could not be
- * accessed (ie. because it is an invalid address).
- *
- * writev-intensive code may want this to prefault several iovecs -- that
- * would be possible (callers must not rely on the fact that _only_ the
- * first iovec will be faulted with the current implementation).
- */
-int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
-{
-       if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
-               char __user *buf = i->iov->iov_base + i->iov_offset;
-               bytes = min(bytes, i->iov->iov_len - i->iov_offset);
-               return fault_in_pages_readable(buf, bytes);
-       }
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_fault_in_readable);
-
-void iov_iter_init(struct iov_iter *i, int direction,
-                       const struct iovec *iov, unsigned long nr_segs,
-                       size_t count)
-{
-       /* It will get better.  Eventually... */
-       if (segment_eq(get_fs(), KERNEL_DS)) {
-               direction |= ITER_KVEC;
-               i->type = direction;
-               i->kvec = (struct kvec *)iov;
-       } else {
-               i->type = direction;
-               i->iov = iov;
-       }
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_init);
-
-static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
-{
-       char *from = kmap_atomic(page);
-       memcpy(to, from + offset, len);
-       kunmap_atomic(from);
-}
-
-static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len)
-{
-       char *to = kmap_atomic(page);
-       memcpy(to + offset, from, len);
-       kunmap_atomic(to);
-}
-
-static void memzero_page(struct page *page, size_t offset, size_t len)
-{
-       char *addr = kmap_atomic(page);
-       memset(addr + offset, 0, len);
-       kunmap_atomic(addr);
-}
-
-size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *from = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len,
-                              v.iov_len),
-               memcpy_to_page(v.bv_page, v.bv_offset,
-                              (from += v.bv_len) - v.bv_len, v.bv_len),
-               memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_to_iter);
-
-size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *to = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base,
-                                v.iov_len),
-               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_from_iter);
-
-size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *to = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_from_user_nocache((to += v.iov_len) - v.iov_len,
-                                        v.iov_base, v.iov_len),
-               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_from_iter_nocache);
-
-size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       if (i->type & (ITER_BVEC|ITER_KVEC)) {
-               void *kaddr = kmap_atomic(page);
-               size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
-               kunmap_atomic(kaddr);
-               return wanted;
-       } else
-               return copy_page_to_iter_iovec(page, offset, bytes, i);
-}
-EXPORT_SYMBOL(copy_page_to_iter);
-
-size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       if (i->type & (ITER_BVEC|ITER_KVEC)) {
-               void *kaddr = kmap_atomic(page);
-               size_t wanted = copy_from_iter(kaddr + offset, bytes, i);
-               kunmap_atomic(kaddr);
-               return wanted;
-       } else
-               return copy_page_from_iter_iovec(page, offset, bytes, i);
-}
-EXPORT_SYMBOL(copy_page_from_iter);
-
-size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
-{
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __clear_user(v.iov_base, v.iov_len),
-               memzero_page(v.bv_page, v.bv_offset, v.bv_len),
-               memset(v.iov_base, 0, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(iov_iter_zero);
-
-size_t iov_iter_copy_from_user_atomic(struct page *page,
-               struct iov_iter *i, unsigned long offset, size_t bytes)
-{
-       char *kaddr = kmap_atomic(page), *p = kaddr + offset;
-       iterate_all_kinds(i, bytes, v,
-               __copy_from_user_inatomic((p += v.iov_len) - v.iov_len,
-                                         v.iov_base, v.iov_len),
-               memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-       kunmap_atomic(kaddr);
-       return bytes;
-}
-EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
-
-void iov_iter_advance(struct iov_iter *i, size_t size)
-{
-       iterate_and_advance(i, size, v, 0, 0, 0)
-}
-EXPORT_SYMBOL(iov_iter_advance);
-
-/*
- * Return the count of just the current iov_iter segment.
- */
-size_t iov_iter_single_seg_count(const struct iov_iter *i)
-{
-       if (i->nr_segs == 1)
-               return i->count;
-       else if (i->type & ITER_BVEC)
-               return min(i->count, i->bvec->bv_len - i->iov_offset);
-       else
-               return min(i->count, i->iov->iov_len - i->iov_offset);
-}
-EXPORT_SYMBOL(iov_iter_single_seg_count);
-
-void iov_iter_kvec(struct iov_iter *i, int direction,
-                       const struct kvec *kvec, unsigned long nr_segs,
-                       size_t count)
-{
-       BUG_ON(!(direction & ITER_KVEC));
-       i->type = direction;
-       i->kvec = kvec;
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_kvec);
-
-void iov_iter_bvec(struct iov_iter *i, int direction,
-                       const struct bio_vec *bvec, unsigned long nr_segs,
-                       size_t count)
-{
-       BUG_ON(!(direction & ITER_BVEC));
-       i->type = direction;
-       i->bvec = bvec;
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_bvec);
-
-unsigned long iov_iter_alignment(const struct iov_iter *i)
-{
-       unsigned long res = 0;
-       size_t size = i->count;
-
-       if (!size)
-               return 0;
-
-       iterate_all_kinds(i, size, v,
-               (res |= (unsigned long)v.iov_base | v.iov_len, 0),
-               res |= v.bv_offset | v.bv_len,
-               res |= (unsigned long)v.iov_base | v.iov_len
-       )
-       return res;
-}
-EXPORT_SYMBOL(iov_iter_alignment);
-
-ssize_t iov_iter_get_pages(struct iov_iter *i,
-                  struct page **pages, size_t maxsize, unsigned maxpages,
-                  size_t *start)
-{
-       if (maxsize > i->count)
-               maxsize = i->count;
-
-       if (!maxsize)
-               return 0;
-
-       iterate_all_kinds(i, maxsize, v, ({
-               unsigned long addr = (unsigned long)v.iov_base;
-               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
-               int n;
-               int res;
-
-               if (len > maxpages * PAGE_SIZE)
-                       len = maxpages * PAGE_SIZE;
-               addr &= ~(PAGE_SIZE - 1);
-               n = DIV_ROUND_UP(len, PAGE_SIZE);
-               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
-               if (unlikely(res < 0))
-                       return res;
-               return (res == n ? len : res * PAGE_SIZE) - *start;
-       0;}),({
-               /* can't be more than PAGE_SIZE */
-               *start = v.bv_offset;
-               get_page(*pages = v.bv_page);
-               return v.bv_len;
-       }),({
-               return -EFAULT;
-       })
-       )
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_get_pages);
-
-static struct page **get_pages_array(size_t n)
-{
-       struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
-       if (!p)
-               p = vmalloc(n * sizeof(struct page *));
-       return p;
-}
-
-ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
-                  struct page ***pages, size_t maxsize,
-                  size_t *start)
-{
-       struct page **p;
-
-       if (maxsize > i->count)
-               maxsize = i->count;
-
-       if (!maxsize)
-               return 0;
-
-       iterate_all_kinds(i, maxsize, v, ({
-               unsigned long addr = (unsigned long)v.iov_base;
-               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
-               int n;
-               int res;
-
-               addr &= ~(PAGE_SIZE - 1);
-               n = DIV_ROUND_UP(len, PAGE_SIZE);
-               p = get_pages_array(n);
-               if (!p)
-                       return -ENOMEM;
-               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
-               if (unlikely(res < 0)) {
-                       kvfree(p);
-                       return res;
-               }
-               *pages = p;
-               return (res == n ? len : res * PAGE_SIZE) - *start;
-       0;}),({
-               /* can't be more than PAGE_SIZE */
-               *start = v.bv_offset;
-               *pages = p = get_pages_array(1);
-               if (!p)
-                       return -ENOMEM;
-               get_page(*p = v.bv_page);
-               return v.bv_len;
-       }),({
-               return -EFAULT;
-       })
-       )
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_get_pages_alloc);
-
-size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
-                              struct iov_iter *i)
-{
-       char *to = addr;
-       __wsum sum, next;
-       size_t off = 0;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       sum = *csum;
-       iterate_and_advance(i, bytes, v, ({
-               int err = 0;
-               next = csum_and_copy_from_user(v.iov_base, 
-                                              (to += v.iov_len) - v.iov_len,
-                                              v.iov_len, 0, &err);
-               if (!err) {
-                       sum = csum_block_add(sum, next, off);
-                       off += v.iov_len;
-               }
-               err ? v.iov_len : 0;
-       }), ({
-               char *p = kmap_atomic(v.bv_page);
-               next = csum_partial_copy_nocheck(p + v.bv_offset,
-                                                (to += v.bv_len) - v.bv_len,
-                                                v.bv_len, 0);
-               kunmap_atomic(p);
-               sum = csum_block_add(sum, next, off);
-               off += v.bv_len;
-       }),({
-               next = csum_partial_copy_nocheck(v.iov_base,
-                                                (to += v.iov_len) - v.iov_len,
-                                                v.iov_len, 0);
-               sum = csum_block_add(sum, next, off);
-               off += v.iov_len;
-       })
-       )
-       *csum = sum;
-       return bytes;
-}
-EXPORT_SYMBOL(csum_and_copy_from_iter);
-
-size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
-                            struct iov_iter *i)
-{
-       char *from = addr;
-       __wsum sum, next;
-       size_t off = 0;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       sum = *csum;
-       iterate_and_advance(i, bytes, v, ({
-               int err = 0;
-               next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
-                                            v.iov_base, 
-                                            v.iov_len, 0, &err);
-               if (!err) {
-                       sum = csum_block_add(sum, next, off);
-                       off += v.iov_len;
-               }
-               err ? v.iov_len : 0;
-       }), ({
-               char *p = kmap_atomic(v.bv_page);
-               next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len,
-                                                p + v.bv_offset,
-                                                v.bv_len, 0);
-               kunmap_atomic(p);
-               sum = csum_block_add(sum, next, off);
-               off += v.bv_len;
-       }),({
-               next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len,
-                                                v.iov_base,
-                                                v.iov_len, 0);
-               sum = csum_block_add(sum, next, off);
-               off += v.iov_len;
-       })
-       )
-       *csum = sum;
-       return bytes;
-}
-EXPORT_SYMBOL(csum_and_copy_to_iter);
-
-int iov_iter_npages(const struct iov_iter *i, int maxpages)
-{
-       size_t size = i->count;
-       int npages = 0;
-
-       if (!size)
-               return 0;
-
-       iterate_all_kinds(i, size, v, ({
-               unsigned long p = (unsigned long)v.iov_base;
-               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
-                       - p / PAGE_SIZE;
-               if (npages >= maxpages)
-                       return maxpages;
-       0;}),({
-               npages++;
-               if (npages >= maxpages)
-                       return maxpages;
-       }),({
-               unsigned long p = (unsigned long)v.iov_base;
-               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
-                       - p / PAGE_SIZE;
-               if (npages >= maxpages)
-                       return maxpages;
-       })
-       )
-       return npages;
-}
-EXPORT_SYMBOL(iov_iter_npages);
index 78fee63..936d816 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/stacktrace.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/vmalloc.h>
 #include <linux/kasan.h>
 
 #include "kasan.h"
@@ -414,12 +415,19 @@ int kasan_module_alloc(void *addr, size_t size)
                        GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
                        PAGE_KERNEL, VM_NO_GUARD, NUMA_NO_NODE,
                        __builtin_return_address(0));
-       return ret ? 0 : -ENOMEM;
+
+       if (ret) {
+               find_vm_area(addr)->flags |= VM_KASAN;
+               return 0;
+       }
+
+       return -ENOMEM;
 }
 
-void kasan_module_free(void *addr)
+void kasan_free_shadow(const struct vm_struct *vm)
 {
-       vfree(kasan_mem_to_shadow(addr));
+       if (vm->flags & VM_KASAN)
+               vfree(kasan_mem_to_shadow(vm->addr));
 }
 
 static void register_global(struct kasan_global *global)
index d18d3a6..b34ef4a 100644 (file)
@@ -5232,7 +5232,9 @@ static void mem_cgroup_bind(struct cgroup_subsys_state *root_css)
         * on for the root memcg is enough.
         */
        if (cgroup_on_dfl(root_css->cgroup))
-               mem_cgroup_from_css(root_css)->use_hierarchy = true;
+               root_mem_cgroup->use_hierarchy = true;
+       else
+               root_mem_cgroup->use_hierarchy = false;
 }
 
 static u64 memory_current_read(struct cgroup_subsys_state *css,
@@ -5247,7 +5249,7 @@ static int memory_low_show(struct seq_file *m, void *v)
        unsigned long low = ACCESS_ONCE(memcg->low);
 
        if (low == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)low * PAGE_SIZE);
 
@@ -5262,7 +5264,7 @@ static ssize_t memory_low_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &low);
+       err = page_counter_memparse(buf, "max", &low);
        if (err)
                return err;
 
@@ -5277,7 +5279,7 @@ static int memory_high_show(struct seq_file *m, void *v)
        unsigned long high = ACCESS_ONCE(memcg->high);
 
        if (high == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)high * PAGE_SIZE);
 
@@ -5292,7 +5294,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &high);
+       err = page_counter_memparse(buf, "max", &high);
        if (err)
                return err;
 
@@ -5307,7 +5309,7 @@ static int memory_max_show(struct seq_file *m, void *v)
        unsigned long max = ACCESS_ONCE(memcg->memory.limit);
 
        if (max == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)max * PAGE_SIZE);
 
@@ -5322,7 +5324,7 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &max);
+       err = page_counter_memparse(buf, "max", &max);
        if (err)
                return err;
 
@@ -5426,7 +5428,7 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
        if (memcg == root_mem_cgroup)
                return false;
 
-       if (page_counter_read(&memcg->memory) > memcg->low)
+       if (page_counter_read(&memcg->memory) >= memcg->low)
                return false;
 
        while (memcg != root) {
@@ -5435,7 +5437,7 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
                if (memcg == root_mem_cgroup)
                        break;
 
-               if (page_counter_read(&memcg->memory) > memcg->low)
+               if (page_counter_read(&memcg->memory) >= memcg->low)
                        return false;
        }
        return true;
index 8068893..97839f5 100644 (file)
@@ -3035,6 +3035,7 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        int last_cpupid;
        int target_nid;
        bool migrated = false;
+       bool was_writable = pte_write(pte);
        int flags = 0;
 
        /* A PROT_NONE fault should not end up here */
@@ -3059,6 +3060,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        /* Make it present again */
        pte = pte_modify(pte, vma->vm_page_prot);
        pte = pte_mkyoung(pte);
+       if (was_writable)
+               pte = pte_mkwrite(pte);
        set_pte_at(mm, addr, ptep, pte);
        update_mmu_cache(vma, addr, ptep);
 
@@ -3069,11 +3072,14 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        }
 
        /*
-        * Avoid grouping on DSO/COW pages in specific and RO pages
-        * in general, RO pages shouldn't hurt as much anyway since
-        * they can be in shared cache state.
+        * Avoid grouping on RO pages in general. RO pages shouldn't hurt as
+        * much anyway since they can be in shared cache state. This misses
+        * the case where a mapping is writable but the process never writes
+        * to it but pte_write gets cleared during protection updates and
+        * pte_dirty has unpredictable behaviour between PTE scan updates,
+        * background writeback, dirty balancing and application behaviour.
         */
-       if (!pte_write(pte))
+       if (!(vma->vm_flags & VM_WRITE))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -3097,7 +3103,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (migrated) {
                page_nid = target_nid;
                flags |= TNF_MIGRATED;
-       }
+       } else
+               flags |= TNF_MIGRATE_FAIL;
 
 out:
        if (page_nid != -1)
index 9fab107..65842d6 100644 (file)
@@ -1092,6 +1092,10 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
                        return NULL;
 
                arch_refresh_nodedata(nid, pgdat);
+       } else {
+               /* Reset the nr_zones and classzone_idx to 0 before reuse */
+               pgdat->nr_zones = 0;
+               pgdat->classzone_idx = 0;
        }
 
        /* we can use NODE_DATA(nid) from here */
@@ -1977,15 +1981,6 @@ void try_offline_node(int nid)
                if (is_vmalloc_addr(zone->wait_table))
                        vfree(zone->wait_table);
        }
-
-       /*
-        * Since there is no way to guarentee the address of pgdat/zone is not
-        * on stack of any kernel threads or used by other kernel objects
-        * without reference counting or other symchronizing method, do not
-        * reset node_data and free pgdat here. Just reset it to 0 and reuse
-        * the memory when the node is online again.
-        */
-       memset(pgdat, 0, sizeof(*pgdat));
 }
 EXPORT_SYMBOL(try_offline_node);
 
index 73cf098..8a54cd2 100644 (file)
 
 int can_do_mlock(void)
 {
-       if (capable(CAP_IPC_LOCK))
-               return 1;
        if (rlimit(RLIMIT_MEMLOCK) != 0)
                return 1;
+       if (capable(CAP_IPC_LOCK))
+               return 1;
        return 0;
 }
 EXPORT_SYMBOL(can_do_mlock);
index da9990a..9ec50a3 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -774,10 +774,8 @@ again:                     remove_next = 1 + (end > next->vm_end);
 
                        importer->anon_vma = exporter->anon_vma;
                        error = anon_vma_clone(importer, exporter);
-                       if (error) {
-                               importer->anon_vma = NULL;
+                       if (error)
                                return error;
-                       }
                }
        }
 
index 4472781..8858483 100644 (file)
@@ -75,6 +75,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                oldpte = *pte;
                if (pte_present(oldpte)) {
                        pte_t ptent;
+                       bool preserve_write = prot_numa && pte_write(oldpte);
 
                        /*
                         * Avoid trapping faults against the zero or KSM
@@ -94,6 +95,8 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 
                        ptent = ptep_modify_prot_start(mm, addr, pte);
                        ptent = pte_modify(ptent, newprot);
+                       if (preserve_write)
+                               ptent = pte_mkwrite(ptent);
 
                        /* Avoid taking write faults for known dirty pages */
                        if (dirty_accountable && pte_dirty(ptent) &&
index 7296360..3fba2dc 100644 (file)
@@ -62,6 +62,7 @@ void *high_memory;
 EXPORT_SYMBOL(high_memory);
 struct page *mem_map;
 unsigned long max_mapnr;
+EXPORT_SYMBOL(max_mapnr);
 unsigned long highest_memmap_pfn;
 struct percpu_counter vm_committed_as;
 int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
@@ -1213,11 +1214,9 @@ static int do_mmap_private(struct vm_area_struct *vma,
        if (sysctl_nr_trim_pages && total - point >= sysctl_nr_trim_pages) {
                total = point;
                kdebug("try to alloc exact %lu pages", total);
-               base = alloc_pages_exact(len, GFP_KERNEL);
-       } else {
-               base = (void *)__get_free_pages(GFP_KERNEL, order);
        }
 
+       base = alloc_pages_exact(total << PAGE_SHIFT, GFP_KERNEL);
        if (!base)
                goto enomem;
 
index 45e187b..644bcb6 100644 (file)
@@ -857,8 +857,11 @@ static void bdi_update_write_bandwidth(struct backing_dev_info *bdi,
         *                   bw * elapsed + write_bandwidth * (period - elapsed)
         * write_bandwidth = ---------------------------------------------------
         *                                          period
+        *
+        * @written may have decreased due to account_page_redirty().
+        * Avoid underflowing @bw calculation.
         */
-       bw = written - bdi->written_stamp;
+       bw = written - min(written, bdi->written_stamp);
        bw *= HZ;
        if (unlikely(elapsed > period)) {
                do_div(bw, elapsed);
@@ -922,7 +925,7 @@ static void global_update_bandwidth(unsigned long thresh,
                                    unsigned long now)
 {
        static DEFINE_SPINLOCK(dirty_lock);
-       static unsigned long update_time;
+       static unsigned long update_time = INITIAL_JIFFIES;
 
        /*
         * check locklessly first to optimize away locking for the most time
index a47f0b2..40e2942 100644 (file)
@@ -2353,8 +2353,15 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
                if (ac->high_zoneidx < ZONE_NORMAL)
                        goto out;
                /* The OOM killer does not compensate for light reclaim */
-               if (!(gfp_mask & __GFP_FS))
+               if (!(gfp_mask & __GFP_FS)) {
+                       /*
+                        * XXX: Page reclaim didn't yield anything,
+                        * and the OOM killer can't be invoked, but
+                        * keep looping as per should_alloc_retry().
+                        */
+                       *did_some_progress = 1;
                        goto out;
+               }
                /*
                 * GFP_THISNODE contains __GFP_NORETRY and we never hit this.
                 * Sanity check for bare calls of __GFP_THISNODE, not real OOM.
@@ -2366,7 +2373,8 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
                        goto out;
        }
        /* Exhausted what can be done so it's blamo time */
-       if (out_of_memory(ac->zonelist, gfp_mask, order, ac->nodemask, false))
+       if (out_of_memory(ac->zonelist, gfp_mask, order, ac->nodemask, false)
+                       || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL))
                *did_some_progress = 1;
 out:
        oom_zonelist_unlock(ac->zonelist, gfp_mask);
index 72f5ac3..755a42c 100644 (file)
@@ -103,6 +103,7 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype)
 
                        if (!is_migrate_isolate_page(buddy)) {
                                __isolate_free_page(page, order);
+                               kernel_map_pages(page, (1 << order), 1);
                                set_page_refcounted(page);
                                isolated_page = page;
                        }
index 75c1f28..29f2f8b 100644 (file)
@@ -265,8 +265,15 @@ int walk_page_range(unsigned long start, unsigned long end,
                        vma = vma->vm_next;
 
                        err = walk_page_test(start, next, walk);
-                       if (err > 0)
+                       if (err > 0) {
+                               /*
+                                * positive return values are purely for
+                                * controlling the pagewalk, so should never
+                                * be passed to the callers.
+                                */
+                               err = 0;
                                continue;
+                       }
                        if (err < 0)
                                break;
                }
index 5e3e090..c161a14 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -287,6 +287,13 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
        return 0;
 
  enomem_failure:
+       /*
+        * dst->anon_vma is dropped here otherwise its degree can be incorrectly
+        * decremented in unlink_anon_vmas().
+        * We can safely do this because callers of anon_vma_clone() don't care
+        * about dst->anon_vma if anon_vma_clone() failed.
+        */
+       dst->anon_vma = NULL;
        unlink_anon_vmas(dst);
        return -ENOMEM;
 }
index 2f17cb5..cf2d0ca 100644 (file)
@@ -1455,6 +1455,9 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
 
 bool shmem_mapping(struct address_space *mapping)
 {
+       if (!mapping->host)
+               return false;
+
        return mapping->host->i_sb->s_op == &shmem_ops;
 }
 
index 6832c4e..82c4737 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2449,7 +2449,8 @@ redo:
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
                c = raw_cpu_ptr(s->cpu_slab);
-       } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid));
+       } while (IS_ENABLED(CONFIG_PREEMPT) &&
+                unlikely(tid != READ_ONCE(c->tid)));
 
        /*
         * Irqless object alloc/free algorithm used here depends on sequence
@@ -2718,7 +2719,8 @@ redo:
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
                c = raw_cpu_ptr(s->cpu_slab);
-       } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid));
+       } while (IS_ENABLED(CONFIG_PREEMPT) &&
+                unlikely(tid != READ_ONCE(c->tid)));
 
        /* Same with comment on barrier() in slab_alloc_node() */
        barrier();
index 35b25e1..49abccf 100644 (file)
@@ -1418,6 +1418,7 @@ struct vm_struct *remove_vm_area(const void *addr)
                spin_unlock(&vmap_area_lock);
 
                vmap_debug_free_range(va->va_start, va->va_end);
+               kasan_free_shadow(vm);
                free_unmap_vmap_area(va);
                vm->size -= PAGE_SIZE;
 
index d8e376a..36a1a73 100644 (file)
@@ -658,14 +658,30 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args)
 static void p9_virtio_remove(struct virtio_device *vdev)
 {
        struct virtio_chan *chan = vdev->priv;
-
-       if (chan->inuse)
-               p9_virtio_close(chan->client);
-       vdev->config->del_vqs(vdev);
+       unsigned long warning_time;
 
        mutex_lock(&virtio_9p_lock);
+
+       /* Remove self from list so we don't get new users. */
        list_del(&chan->chan_list);
+       warning_time = jiffies;
+
+       /* Wait for existing users to close. */
+       while (chan->inuse) {
+               mutex_unlock(&virtio_9p_lock);
+               msleep(250);
+               if (time_after(jiffies, warning_time + 10 * HZ)) {
+                       dev_emerg(&vdev->dev,
+                                 "p9_virtio_remove: waiting for device in use.\n");
+                       warning_time = jiffies;
+               }
+               mutex_lock(&virtio_9p_lock);
+       }
+
        mutex_unlock(&virtio_9p_lock);
+
+       vdev->config->del_vqs(vdev);
+
        sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
        kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
        kfree(chan->tag);
index fb57ab6..02c24cf 100644 (file)
@@ -190,6 +190,8 @@ static int __init br_init(void)
 {
        int err;
 
+       BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));
+
        err = stp_proto_register(&br_stp_proto);
        if (err < 0) {
                pr_err("bridge: can't register sap for STP\n");
index b087d27..1849d96 100644 (file)
@@ -563,6 +563,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
         */
        del_nbp(p);
 
+       dev_set_mtu(br->dev, br_min_mtu(br));
+
        spin_lock_bh(&br->lock);
        changed_addr = br_stp_recalculate_bridge_id(br);
        spin_unlock_bh(&br->lock);
index 769b185..a6e2da0 100644 (file)
@@ -281,7 +281,7 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
        int copylen;
 
        ret = -EOPNOTSUPP;
-       if (m->msg_flags&MSG_OOB)
+       if (flags & MSG_OOB)
                goto read_error;
 
        skb = skb_recv_datagram(sk, flags, 0 , &ret);
index 8bc7caa..434ba85 100644 (file)
@@ -84,7 +84,7 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
        u16 tmp;
        u16 len;
        u16 hdrchks;
-       u16 pktchks;
+       int pktchks;
        struct cffrml *this;
        this = container_obj(layr);
 
index 1be0b52..f6c3b21 100644 (file)
@@ -255,9 +255,9 @@ inline u16 cfpkt_getlen(struct cfpkt *pkt)
        return skb->len;
 }
 
-inline u16 cfpkt_iterate(struct cfpkt *pkt,
-                        u16 (*iter_func)(u16, void *, u16),
-                        u16 data)
+int cfpkt_iterate(struct cfpkt *pkt,
+                 u16 (*iter_func)(u16, void *, u16),
+                 u16 data)
 {
        /*
         * Don't care about the performance hit of linearizing,
index 66e0804..32d710e 100644 (file)
@@ -259,6 +259,9 @@ int can_send(struct sk_buff *skb, int loop)
                goto inval_skb;
        }
 
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
        skb_reset_transport_header(skb);
 
index 3236b41..f7bd286 100644 (file)
@@ -49,6 +49,13 @@ ssize_t get_compat_msghdr(struct msghdr *kmsg,
            __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
            __get_user(kmsg->msg_flags, &umsg->msg_flags))
                return -EFAULT;
+
+       if (!uaddr)
+               kmsg->msg_namelen = 0;
+
+       if (kmsg->msg_namelen < 0)
+               return -EINVAL;
+
        if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
        kmsg->msg_control = compat_ptr(tmp3);
@@ -711,24 +718,18 @@ static unsigned char nas[21] = {
 
 COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
 COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
                       unsigned int, vlen, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                              flags | MSG_CMSG_COMPAT);
 }
 
 COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
@@ -751,9 +752,6 @@ COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
        int datagrams;
        struct timespec ktspec;
 
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
-
        if (timeout == NULL)
                return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                      flags | MSG_CMSG_COMPAT, NULL);
index 8f9710c..45109b7 100644 (file)
@@ -946,7 +946,7 @@ bool dev_valid_name(const char *name)
                return false;
 
        while (*name) {
-               if (*name == '/' || isspace(*name))
+               if (*name == '/' || *name == ':' || isspace(*name))
                        return false;
                name++;
        }
@@ -2848,7 +2848,9 @@ static void skb_update_prio(struct sk_buff *skb)
 #define skb_update_prio(skb)
 #endif
 
-static DEFINE_PER_CPU(int, xmit_recursion);
+DEFINE_PER_CPU(int, xmit_recursion);
+EXPORT_SYMBOL(xmit_recursion);
+
 #define RECURSION_LIMIT 10
 
 /**
index 91f74f3..aa378ec 100644 (file)
@@ -98,6 +98,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
        [NETIF_F_RXALL_BIT] =            "rx-all",
        [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
        [NETIF_F_BUSY_POLL_BIT] =        "busy-poll",
+       [NETIF_F_HW_SWITCH_OFFLOAD_BIT] = "hw-switch-offload",
 };
 
 static const char
index 44706e8..e4fdc9d 100644 (file)
@@ -175,9 +175,9 @@ void fib_rules_unregister(struct fib_rules_ops *ops)
 
        spin_lock(&net->rules_mod_lock);
        list_del_rcu(&ops->list);
-       fib_rules_cleanup_ops(ops);
        spin_unlock(&net->rules_mod_lock);
 
+       fib_rules_cleanup_ops(ops);
        call_rcu(&ops->rcu, fib_rules_put_rcu);
 }
 EXPORT_SYMBOL_GPL(fib_rules_unregister);
index 0c08062..1e2f46a 100644 (file)
@@ -32,6 +32,9 @@ gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)
        return 0;
 
 nla_put_failure:
+       kfree(d->xstats);
+       d->xstats = NULL;
+       d->xstats_len = 0;
        spin_unlock_bh(d->lock);
        return -1;
 }
@@ -305,7 +308,9 @@ int
 gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
 {
        if (d->compat_xstats) {
-               d->xstats = st;
+               d->xstats = kmemdup(st, len, GFP_ATOMIC);
+               if (!d->xstats)
+                       goto err_out;
                d->xstats_len = len;
        }
 
@@ -313,6 +318,11 @@ gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
                return gnet_stats_copy(d, TCA_STATS_APP, st, len);
 
        return 0;
+
+err_out:
+       d->xstats_len = 0;
+       spin_unlock_bh(d->lock);
+       return -1;
 }
 EXPORT_SYMBOL(gnet_stats_copy_app);
 
@@ -345,6 +355,9 @@ gnet_stats_finish_copy(struct gnet_dump *d)
                        return -1;
        }
 
+       kfree(d->xstats);
+       d->xstats = NULL;
+       d->xstats_len = 0;
        spin_unlock_bh(d->lock);
        return 0;
 }
index cb5290b..70d3450 100644 (file)
@@ -198,8 +198,10 @@ static int __peernet2id(struct net *net, struct net *peer, bool alloc)
  */
 int peernet2id(struct net *net, struct net *peer)
 {
-       int id = __peernet2id(net, peer, true);
+       bool alloc = atomic_read(&peer->count) == 0 ? false : true;
+       int id;
 
+       id = __peernet2id(net, peer, alloc);
        return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED;
 }
 EXPORT_SYMBOL(peernet2id);
index b4899f5..508155b 100644 (file)
@@ -1134,6 +1134,9 @@ static ssize_t pktgen_if_write(struct file *file,
                        return len;
 
                i += len;
+               if ((value > 1) &&
+                   (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
+                       return -ENOTSUPP;
                pkt_dev->burst = value < 1 ? 1 : value;
                sprintf(pg_result, "OK: burst=%d", pkt_dev->burst);
                return count;
index ab293a3..7ebed55 100644 (file)
@@ -1300,7 +1300,6 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        s_h = cb->args[0];
        s_idx = cb->args[1];
 
-       rcu_read_lock();
        cb->seq = net->dev_base_seq;
 
        /* A hack to preserve kernel<->userspace interface.
@@ -1322,7 +1321,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
                idx = 0;
                head = &net->dev_index_head[h];
-               hlist_for_each_entry_rcu(dev, head, index_hlist) {
+               hlist_for_each_entry(dev, head, index_hlist) {
                        if (idx < s_idx)
                                goto cont;
                        err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
@@ -1344,7 +1343,6 @@ cont:
                }
        }
 out:
-       rcu_read_unlock();
        cb->args[1] = idx;
        cb->args[0] = h;
 
@@ -1934,10 +1932,10 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
                struct ifinfomsg *ifm,
                struct nlattr **tb)
 {
-       struct net_device *dev;
+       struct net_device *dev, *aux;
        int err;
 
-       for_each_netdev(net, dev) {
+       for_each_netdev_safe(net, dev, aux) {
                if (dev->group == group) {
                        err = do_setlink(skb, dev, ifm, tb, NULL, 0);
                        if (err < 0)
@@ -2012,8 +2010,8 @@ replay:
        }
 
        if (1) {
-               struct nlattr *attr[ops ? ops->maxtype + 1 : 0];
-               struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 0];
+               struct nlattr *attr[ops ? ops->maxtype + 1 : 1];
+               struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 1];
                struct nlattr **data = NULL;
                struct nlattr **slave_data = NULL;
                struct net *dest_net, *link_net = NULL;
@@ -2122,6 +2120,10 @@ replay:
                if (IS_ERR(dest_net))
                        return PTR_ERR(dest_net);
 
+               err = -EPERM;
+               if (!netlink_ns_capable(skb, dest_net->user_ns, CAP_NET_ADMIN))
+                       goto out;
+
                if (tb[IFLA_LINK_NETNSID]) {
                        int id = nla_get_s32(tb[IFLA_LINK_NETNSID]);
 
@@ -2130,6 +2132,9 @@ replay:
                                err =  -EINVAL;
                                goto out;
                        }
+                       err = -EPERM;
+                       if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN))
+                               goto out;
                }
 
                dev = rtnl_create_link(link_net ? : dest_net, ifname,
@@ -2161,28 +2166,28 @@ replay:
                        }
                }
                err = rtnl_configure_link(dev, ifm);
-               if (err < 0) {
-                       if (ops->newlink) {
-                               LIST_HEAD(list_kill);
-
-                               ops->dellink(dev, &list_kill);
-                               unregister_netdevice_many(&list_kill);
-                       } else {
-                               unregister_netdevice(dev);
-                       }
-                       goto out;
-               }
-
+               if (err < 0)
+                       goto out_unregister;
                if (link_net) {
                        err = dev_change_net_namespace(dev, dest_net, ifname);
                        if (err < 0)
-                               unregister_netdevice(dev);
+                               goto out_unregister;
                }
 out:
                if (link_net)
                        put_net(link_net);
                put_net(dest_net);
                return err;
+out_unregister:
+               if (ops->newlink) {
+                       LIST_HEAD(list_kill);
+
+                       ops->dellink(dev, &list_kill);
+                       unregister_netdevice_many(&list_kill);
+               } else {
+                       unregister_netdevice(dev);
+               }
+               goto out;
        }
 }
 
index 88c613e..8e4ac97 100644 (file)
@@ -3621,13 +3621,14 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
 {
        struct sk_buff_head *q = &sk->sk_error_queue;
        struct sk_buff *skb, *skb_next;
+       unsigned long flags;
        int err = 0;
 
-       spin_lock_bh(&q->lock);
+       spin_lock_irqsave(&q->lock, flags);
        skb = __skb_dequeue(q);
        if (skb && (skb_next = skb_peek(q)))
                err = SKB_EXT_ERR(skb_next)->ee.ee_errno;
-       spin_unlock_bh(&q->lock);
+       spin_unlock_irqrestore(&q->lock, flags);
 
        sk->sk_err = err;
        if (err)
@@ -3732,9 +3733,13 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
                     struct sock *sk, int tstype)
 {
        struct sk_buff *skb;
-       bool tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       bool tsonly;
+
+       if (!sk)
+               return;
 
-       if (!sk || !skb_may_tx_timestamp(sk, tsonly))
+       tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       if (!skb_may_tx_timestamp(sk, tsonly))
                return;
 
        if (tsonly)
@@ -4172,7 +4177,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
        skb->ignore_df = 0;
        skb_dst_drop(skb);
        skb->mark = 0;
-       skb->sender_cpu = 0;
+       skb_sender_cpu_clear(skb);
        skb_init_secmark(skb);
        secpath_reset(skb);
        nf_reset(skb);
index 93c8b20..71e3e5f 100644 (file)
@@ -653,6 +653,25 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool)
                sock_reset_flag(sk, bit);
 }
 
+bool sk_mc_loop(struct sock *sk)
+{
+       if (dev_recursion_level())
+               return false;
+       if (!sk)
+               return true;
+       switch (sk->sk_family) {
+       case AF_INET:
+               return inet_sk(sk)->mc_loop;
+#if IS_ENABLED(CONFIG_IPV6)
+       case AF_INET6:
+               return inet6_sk(sk)->mc_loop;
+#endif
+       }
+       WARN_ON(1);
+       return true;
+}
+EXPORT_SYMBOL(sk_mc_loop);
+
 /*
  *     This is meant for all protocols to use and covers goings on
  *     at the socket level. Everything here is generic.
@@ -1655,6 +1674,10 @@ void sock_rfree(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_rfree);
 
+/*
+ * Buffer destructor for skbs that are not used directly in read or write
+ * path, e.g. for error handler skbs. Automatically called from kfree_skb.
+ */
 void sock_efree(struct sk_buff *skb)
 {
        sock_put(skb->sk);
index 4334248..8ce351f 100644 (file)
@@ -25,6 +25,8 @@
 static int zero = 0;
 static int one = 1;
 static int ushort_max = USHRT_MAX;
+static int min_sndbuf = SOCK_MIN_SNDBUF;
+static int min_rcvbuf = SOCK_MIN_RCVBUF;
 
 static int net_msg_warn;       /* Unused, but still a sysctl */
 
@@ -237,7 +239,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_sndbuf,
        },
        {
                .procname       = "rmem_max",
@@ -245,7 +247,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_rcvbuf,
        },
        {
                .procname       = "wmem_default",
@@ -253,7 +255,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_sndbuf,
        },
        {
                .procname       = "rmem_default",
@@ -261,7 +263,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_rcvbuf,
        },
        {
                .procname       = "dev_weight",
index 1d7c125..3b81092 100644 (file)
@@ -1062,7 +1062,7 @@ source_ok:
        if (decnet_debug_level & 16)
                printk(KERN_DEBUG
                       "dn_route_output_slow: initial checks complete."
-                      " dst=%o4x src=%04x oif=%d try_hard=%d\n",
+                      " dst=%04x src=%04x oif=%d try_hard=%d\n",
                       le16_to_cpu(fld.daddr), le16_to_cpu(fld.saddr),
                       fld.flowidn_oif, try_hard);
 
index faf7cc3..9d66a0f 100644 (file)
@@ -248,7 +248,9 @@ void __init dn_fib_rules_init(void)
 
 void __exit dn_fib_rules_cleanup(void)
 {
+       rtnl_lock();
        fib_rules_unregister(dn_fib_rules_ops);
+       rtnl_unlock();
        rcu_barrier();
 }
 
index 2173402..4dea2e0 100644 (file)
@@ -501,12 +501,10 @@ static struct net_device *dev_to_net_device(struct device *dev)
 #ifdef CONFIG_OF
 static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
                                        struct dsa_chip_data *cd,
-                                       int chip_index,
+                                       int chip_index, int port_index,
                                        struct device_node *link)
 {
-       int ret;
        const __be32 *reg;
-       int link_port_addr;
        int link_sw_addr;
        struct device_node *parent_sw;
        int len;
@@ -519,6 +517,10 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
        if (!reg || (len != sizeof(*reg) * 2))
                return -EINVAL;
 
+       /*
+        * Get the destination switch number from the second field of its 'reg'
+        * property, i.e. for "reg = <0x19 1>" sw_addr is '1'.
+        */
        link_sw_addr = be32_to_cpup(reg + 1);
 
        if (link_sw_addr >= pd->nr_chips)
@@ -535,20 +537,9 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
                memset(cd->rtable, -1, pd->nr_chips * sizeof(s8));
        }
 
-       reg = of_get_property(link, "reg", NULL);
-       if (!reg) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       link_port_addr = be32_to_cpup(reg);
-
-       cd->rtable[link_sw_addr] = link_port_addr;
+       cd->rtable[link_sw_addr] = port_index;
 
        return 0;
-out:
-       kfree(cd->rtable);
-       return ret;
 }
 
 static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
@@ -658,7 +649,7 @@ static int dsa_of_probe(struct platform_device *pdev)
                        if (!strcmp(port_name, "dsa") && link &&
                                        pd->nr_chips > 1) {
                                ret = dsa_of_setup_routing_table(pd, cd,
-                                               chip_index, link);
+                                               chip_index, port_index, link);
                                if (ret)
                                        goto out_free_chip;
                        }
index a138d75..44d2746 100644 (file)
@@ -359,8 +359,11 @@ static void hsr_dev_destroy(struct net_device *hsr_dev)
        struct hsr_port *port;
 
        hsr = netdev_priv(hsr_dev);
+
+       rtnl_lock();
        hsr_for_each_port(hsr, port)
                hsr_del_port(port);
+       rtnl_unlock();
 
        del_timer_sync(&hsr->prune_timer);
        del_timer_sync(&hsr->announce_timer);
index 779d28b..cd37d00 100644 (file)
@@ -36,6 +36,10 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
                        return NOTIFY_DONE;     /* Not an HSR device */
                hsr = netdev_priv(dev);
                port = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
+               if (port == NULL) {
+                       /* Resend of notification concerning removed device? */
+                       return NOTIFY_DONE;
+               }
        } else {
                hsr = port->hsr;
        }
index a348dcb..7d37366 100644 (file)
@@ -181,8 +181,10 @@ void hsr_del_port(struct hsr_port *port)
        list_del_rcu(&port->port_list);
 
        if (port != master) {
-               netdev_update_features(master->dev);
-               dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
+               if (master != NULL) {
+                       netdev_update_features(master->dev);
+                       dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
+               }
                netdev_rx_handler_unregister(port->dev);
                dev_set_promiscuity(port->dev, -1);
        }
@@ -192,5 +194,7 @@ void hsr_del_port(struct hsr_port *port)
         */
 
        synchronize_rcu();
-       dev_put(port->dev);
+
+       if (port != master)
+               dev_put(port->dev);
 }
index 57be71d..23b9b3e 100644 (file)
@@ -1111,11 +1111,10 @@ static void ip_fib_net_exit(struct net *net)
 {
        unsigned int i;
 
+       rtnl_lock();
 #ifdef CONFIG_IP_MULTIPLE_TABLES
        fib4_rules_exit(net);
 #endif
-
-       rtnl_lock();
        for (i = 0; i < FIB_TABLE_HASHSZ; i++) {
                struct fib_table *tb;
                struct hlist_head *head;
index 14d02ea..3e44b9b 100644 (file)
@@ -268,6 +268,7 @@ static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
                release_sock(sk);
                if (reqsk_queue_empty(&icsk->icsk_accept_queue))
                        timeo = schedule_timeout(timeo);
+               sched_annotate_sleep();
                lock_sock(sk);
                err = 0;
                if (!reqsk_queue_empty(&icsk->icsk_accept_queue))
index 81751f1..592aff3 100644 (file)
@@ -71,6 +71,20 @@ static inline void inet_diag_unlock_handler(
        mutex_unlock(&inet_diag_table_mutex);
 }
 
+static size_t inet_sk_attr_size(void)
+{
+       return    nla_total_size(sizeof(struct tcp_info))
+               + nla_total_size(1) /* INET_DIAG_SHUTDOWN */
+               + nla_total_size(1) /* INET_DIAG_TOS */
+               + nla_total_size(1) /* INET_DIAG_TCLASS */
+               + nla_total_size(sizeof(struct inet_diag_meminfo))
+               + nla_total_size(sizeof(struct inet_diag_msg))
+               + nla_total_size(SK_MEMINFO_VARS * sizeof(u32))
+               + nla_total_size(TCP_CA_NAME_MAX)
+               + nla_total_size(sizeof(struct tcpvegas_info))
+               + 64;
+}
+
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                              struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              struct user_namespace *user_ns,                   
@@ -326,9 +340,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s
        if (err)
                goto out;
 
-       rep = nlmsg_new(sizeof(struct inet_diag_msg) +
-                       sizeof(struct inet_diag_meminfo) +
-                       sizeof(struct tcp_info) + 64, GFP_KERNEL);
+       rep = nlmsg_new(inet_sk_attr_size(), GFP_KERNEL);
        if (!rep) {
                err = -ENOMEM;
                goto out;
index 787b3c2..d9bc28a 100644 (file)
@@ -67,6 +67,7 @@ static int ip_forward_finish(struct sk_buff *skb)
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
 
+       skb_sender_cpu_clear(skb);
        return dst_output(skb);
 }
 
index e5b6d0d..145a50c 100644 (file)
@@ -659,27 +659,30 @@ EXPORT_SYMBOL(ip_defrag);
 struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user)
 {
        struct iphdr iph;
+       int netoff;
        u32 len;
 
        if (skb->protocol != htons(ETH_P_IP))
                return skb;
 
-       if (!skb_copy_bits(skb, 0, &iph, sizeof(iph)))
+       netoff = skb_network_offset(skb);
+
+       if (skb_copy_bits(skb, netoff, &iph, sizeof(iph)) < 0)
                return skb;
 
        if (iph.ihl < 5 || iph.version != 4)
                return skb;
 
        len = ntohs(iph.tot_len);
-       if (skb->len < len || len < (iph.ihl * 4))
+       if (skb->len < netoff + len || len < (iph.ihl * 4))
                return skb;
 
        if (ip_is_fragment(&iph)) {
                skb = skb_share_check(skb, GFP_ATOMIC);
                if (skb) {
-                       if (!pskb_may_pull(skb, iph.ihl*4))
+                       if (!pskb_may_pull(skb, netoff + iph.ihl * 4))
                                return skb;
-                       if (pskb_trim_rcsum(skb, len))
+                       if (pskb_trim_rcsum(skb, netoff + len))
                                return skb;
                        memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
                        if (ip_defrag(skb, user))
index d68199d..a7aea20 100644 (file)
@@ -888,7 +888,8 @@ static int __ip_append_data(struct sock *sk,
        cork->length += length;
        if (((length > mtu) || (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
-           (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) {
+           (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
+           (sk->sk_type == SOCK_DGRAM)) {
                err = ip_ufo_append_data(sk, queue, getfrag, from, length,
                                         hh_len, fragheaderlen, transhdrlen,
                                         maxfraglen, flags);
index 31d8c71..5cd9927 100644 (file)
@@ -432,17 +432,32 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf
                kfree_skb(skb);
 }
 
-static bool ipv4_pktinfo_prepare_errqueue(const struct sock *sk,
-                                         const struct sk_buff *skb,
-                                         int ee_origin)
+/* IPv4 supports cmsg on all imcp errors and some timestamps
+ *
+ * Timestamp code paths do not initialize the fields expected by cmsg:
+ * the PKTINFO fields in skb->cb[]. Fill those in here.
+ */
+static bool ipv4_datagram_support_cmsg(const struct sock *sk,
+                                      struct sk_buff *skb,
+                                      int ee_origin)
 {
-       struct in_pktinfo *info = PKTINFO_SKB_CB(skb);
+       struct in_pktinfo *info;
+
+       if (ee_origin == SO_EE_ORIGIN_ICMP)
+               return true;
 
-       if ((ee_origin != SO_EE_ORIGIN_TIMESTAMPING) ||
-           (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) ||
+       if (ee_origin == SO_EE_ORIGIN_LOCAL)
+               return false;
+
+       /* Support IP_PKTINFO on tstamp packets if requested, to correlate
+        * timestamp with egress dev. Not possible for packets without dev
+        * or without payload (SOF_TIMESTAMPING_OPT_TSONLY).
+        */
+       if ((!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) ||
            (!skb->dev))
                return false;
 
+       info = PKTINFO_SKB_CB(skb);
        info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr;
        info->ipi_ifindex = skb->dev->ifindex;
        return true;
@@ -483,7 +498,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        serr = SKB_EXT_ERR(skb);
 
-       if (sin && skb->len) {
+       if (sin && serr->port) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
                                                   serr->addr_offset);
@@ -496,9 +511,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        sin = &errhdr.offender;
        memset(sin, 0, sizeof(*sin));
 
-       if (skb->len &&
-           (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
-            ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin))) {
+       if (ipv4_datagram_support_cmsg(sk, skb, serr->ee.ee_origin)) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
                if (inet_sk(sk)->cmsg_flags)
index 9d78427..fe54eba 100644 (file)
@@ -268,7 +268,7 @@ static int __net_init ipmr_rules_init(struct net *net)
        return 0;
 
 err2:
-       kfree(mrt);
+       ipmr_free_table(mrt);
 err1:
        fib_rules_unregister(ops);
        return err;
@@ -278,11 +278,13 @@ static void __net_exit ipmr_rules_exit(struct net *net)
 {
        struct mr_table *mrt, *next;
 
+       rtnl_lock();
        list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
                list_del(&mrt->list);
                ipmr_free_table(mrt);
        }
        fib_rules_unregister(net->ipv4.mr_rules_ops);
+       rtnl_unlock();
 }
 #else
 #define ipmr_for_each_table(mrt, net) \
@@ -308,7 +310,10 @@ static int __net_init ipmr_rules_init(struct net *net)
 
 static void __net_exit ipmr_rules_exit(struct net *net)
 {
+       rtnl_lock();
        ipmr_free_table(net->ipv4.mrt);
+       net->ipv4.mrt = NULL;
+       rtnl_unlock();
 }
 #endif
 
index 99e810f..cf5e82f 100644 (file)
@@ -272,9 +272,9 @@ static void trace_packet(const struct sk_buff *skb,
                    &chainname, &comment, &rulenum) != 0)
                        break;
 
-       nf_log_packet(net, AF_INET, hook, skb, in, out, &trace_loginfo,
-                     "TRACE: %s:%s:%s:%u ",
-                     tablename, chainname, comment, rulenum);
+       nf_log_trace(net, AF_INET, hook, skb, in, out, &trace_loginfo,
+                    "TRACE: %s:%s:%s:%u ",
+                    tablename, chainname, comment, rulenum);
 }
 #endif
 
index e9f66e1..208d543 100644 (file)
@@ -259,6 +259,9 @@ int ping_init_sock(struct sock *sk)
        kgid_t low, high;
        int ret = 0;
 
+       if (sk->sk_family == AF_INET6)
+               sk->sk_ipv6only = 1;
+
        inet_get_ping_group_range_net(net, &low, &high);
        if (gid_lte(low, group) && gid_lte(group, high))
                return 0;
@@ -305,6 +308,11 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
                if (addr_len < sizeof(*addr))
                        return -EINVAL;
 
+               if (addr->sin_family != AF_INET &&
+                   !(addr->sin_family == AF_UNSPEC &&
+                     addr->sin_addr.s_addr == htonl(INADDR_ANY)))
+                       return -EAFNOSUPPORT;
+
                pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n",
                         sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
 
@@ -330,7 +338,7 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
                        return -EINVAL;
 
                if (addr->sin6_family != AF_INET6)
-                       return -EINVAL;
+                       return -EAFNOSUPPORT;
 
                pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n",
                         sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
@@ -716,7 +724,7 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
                if (msg->msg_namelen < sizeof(*usin))
                        return -EINVAL;
                if (usin->sin_family != AF_INET)
-                       return -EINVAL;
+                       return -EAFNOSUPPORT;
                daddr = usin->sin_addr.s_addr;
                /* no remote port */
        } else {
index 9d72a0f..995a225 100644 (file)
@@ -835,17 +835,13 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
                                       int large_allowed)
 {
        struct tcp_sock *tp = tcp_sk(sk);
-       u32 new_size_goal, size_goal, hlen;
+       u32 new_size_goal, size_goal;
 
        if (!large_allowed || !sk_can_gso(sk))
                return mss_now;
 
-       /* Maybe we should/could use sk->sk_prot->max_header here ? */
-       hlen = inet_csk(sk)->icsk_af_ops->net_header_len +
-              inet_csk(sk)->icsk_ext_hdr_len +
-              tp->tcp_header_len;
-
-       new_size_goal = sk->sk_gso_max_size - 1 - hlen;
+       /* Note : tcp_tso_autosize() will eventually split this later */
+       new_size_goal = sk->sk_gso_max_size - 1 - MAX_TCP_HEADER;
        new_size_goal = tcp_bound_to_half_wnd(tp, new_size_goal);
 
        /* We try hard to avoid divides here */
index d694088..62856e1 100644 (file)
@@ -378,6 +378,12 @@ EXPORT_SYMBOL_GPL(tcp_slow_start);
  */
 void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked)
 {
+       /* If credits accumulated at a higher w, apply them gently now. */
+       if (tp->snd_cwnd_cnt >= w) {
+               tp->snd_cwnd_cnt = 0;
+               tp->snd_cwnd++;
+       }
+
        tp->snd_cwnd_cnt += acked;
        if (tp->snd_cwnd_cnt >= w) {
                u32 delta = tp->snd_cwnd_cnt / w;
index 4b276d1..06d3d66 100644 (file)
@@ -306,8 +306,10 @@ tcp_friendliness:
                }
        }
 
-       if (ca->cnt == 0)                       /* cannot be zero */
-               ca->cnt = 1;
+       /* The maximum rate of cwnd increase CUBIC allows is 1 packet per
+        * 2 packets ACKed, meaning cwnd grows at 1.5x per RTT.
+        */
+       ca->cnt = max(ca->cnt, 2U);
 }
 
 static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
index 8fdd27b..f501ac0 100644 (file)
@@ -3105,10 +3105,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                        if (!first_ackt.v64)
                                first_ackt = last_ackt;
 
-                       if (!(sacked & TCPCB_SACKED_ACKED))
+                       if (!(sacked & TCPCB_SACKED_ACKED)) {
                                reord = min(pkts_acked, reord);
-                       if (!after(scb->end_seq, tp->high_seq))
-                               flag |= FLAG_ORIG_SACK_ACKED;
+                               if (!after(scb->end_seq, tp->high_seq))
+                                       flag |= FLAG_ORIG_SACK_ACKED;
+                       }
                }
 
                if (sacked & TCPCB_SACKED_ACKED)
@@ -4770,7 +4771,7 @@ static bool tcp_should_expand_sndbuf(const struct sock *sk)
                return false;
 
        /* If we filled the congestion window, do not expand.  */
-       if (tp->packets_out >= tp->snd_cwnd)
+       if (tcp_packets_in_flight(tp) >= tp->snd_cwnd)
                return false;
 
        return true;
index 5a2dfed..f1756ee 100644 (file)
@@ -1518,7 +1518,7 @@ void tcp_v4_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk->sk_state != TCP_TIME_WAIT) {
-                       struct dst_entry *dst = sk->sk_rx_dst;
+                       struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, 0);
index a2a796c..1db253e 100644 (file)
@@ -2773,15 +2773,11 @@ void tcp_send_fin(struct sock *sk)
        } else {
                /* Socket is locked, keep trying until memory is available. */
                for (;;) {
-                       skb = alloc_skb_fclone(MAX_TCP_HEADER,
-                                              sk->sk_allocation);
+                       skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
                        if (skb)
                                break;
                        yield();
                }
-
-               /* Reserve space for headers and prepare control bits. */
-               skb_reserve(skb, MAX_TCP_HEADER);
                /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
                tcp_init_nondata_skb(skb, tp->write_seq,
                                     TCPHDR_ACK | TCPHDR_FIN);
index d5f6bd9..dab7381 100644 (file)
@@ -63,6 +63,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
+       skb->protocol = htons(ETH_P_IP);
 
        return x->outer_mode->output2(x, skb);
 }
@@ -71,7 +72,6 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
 int xfrm4_output_finish(struct sk_buff *skb)
 {
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-       skb->protocol = htons(ETH_P_IP);
 
 #ifdef CONFIG_NETFILTER
        IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
index 98e4a63..b603002 100644 (file)
@@ -4903,6 +4903,21 @@ int addrconf_sysctl_forward(struct ctl_table *ctl, int write,
        return ret;
 }
 
+static
+int addrconf_sysctl_mtu(struct ctl_table *ctl, int write,
+                       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct inet6_dev *idev = ctl->extra1;
+       int min_mtu = IPV6_MIN_MTU;
+       struct ctl_table lctl;
+
+       lctl = *ctl;
+       lctl.extra1 = &min_mtu;
+       lctl.extra2 = idev ? &idev->dev->mtu : NULL;
+
+       return proc_dointvec_minmax(&lctl, write, buffer, lenp, ppos);
+}
+
 static void dev_disable_change(struct inet6_dev *idev)
 {
        struct netdev_notifier_info info;
@@ -5054,7 +5069,7 @@ static struct addrconf_sysctl_table
                        .data           = &ipv6_devconf.mtu6,
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .proc_handler   = addrconf_sysctl_mtu,
                },
                {
                        .procname       = "accept_ra",
index c215be7..ace8dac 100644 (file)
@@ -325,14 +325,34 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
        kfree_skb(skb);
 }
 
-static void ip6_datagram_prepare_pktinfo_errqueue(struct sk_buff *skb)
+/* IPv6 supports cmsg on all origins aside from SO_EE_ORIGIN_LOCAL.
+ *
+ * At one point, excluding local errors was a quick test to identify icmp/icmp6
+ * errors. This is no longer true, but the test remained, so the v6 stack,
+ * unlike v4, also honors cmsg requests on all wifi and timestamp errors.
+ *
+ * Timestamp code paths do not initialize the fields expected by cmsg:
+ * the PKTINFO fields in skb->cb[]. Fill those in here.
+ */
+static bool ip6_datagram_support_cmsg(struct sk_buff *skb,
+                                     struct sock_exterr_skb *serr)
 {
-       int ifindex = skb->dev ? skb->dev->ifindex : -1;
+       if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
+           serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6)
+               return true;
+
+       if (serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL)
+               return false;
+
+       if (!skb->dev)
+               return false;
 
        if (skb->protocol == htons(ETH_P_IPV6))
-               IP6CB(skb)->iif = ifindex;
+               IP6CB(skb)->iif = skb->dev->ifindex;
        else
-               PKTINFO_SKB_CB(skb)->ipi_ifindex = ifindex;
+               PKTINFO_SKB_CB(skb)->ipi_ifindex = skb->dev->ifindex;
+
+       return true;
 }
 
 /*
@@ -369,7 +389,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        serr = SKB_EXT_ERR(skb);
 
-       if (sin && skb->len) {
+       if (sin && serr->port) {
                const unsigned char *nh = skb_network_header(skb);
                sin->sin6_family = AF_INET6;
                sin->sin6_flowinfo = 0;
@@ -394,14 +414,11 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
        memset(sin, 0, sizeof(*sin));
-       if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL && skb->len) {
+
+       if (ip6_datagram_support_cmsg(skb, serr)) {
                sin->sin6_family = AF_INET6;
-               if (np->rxopt.all) {
-                       if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
-                           serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6)
-                               ip6_datagram_prepare_pktinfo_errqueue(skb);
+               if (np->rxopt.all)
                        ip6_datagram_recv_common_ctl(sk, msg, skb);
-               }
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        sin->sin6_addr = ipv6_hdr(skb)->saddr;
                        if (np->rxopt.all)
index b4d5e1d..70bc6ab 100644 (file)
@@ -104,6 +104,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
                                goto again;
                        flp6->saddr = saddr;
                }
+               err = rt->dst.error;
                goto out;
        }
 again:
@@ -321,7 +322,9 @@ out_fib6_rules_ops:
 
 static void __net_exit fib6_rules_net_exit(struct net *net)
 {
+       rtnl_lock();
        fib_rules_unregister(net->ipv6.fib6_rules_ops);
+       rtnl_unlock();
 }
 
 static struct pernet_operations fib6_rules_net_ops = {
index 7deebf1..36cf0ab 100644 (file)
@@ -318,6 +318,7 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)
 
 static inline int ip6_forward_finish(struct sk_buff *skb)
 {
+       skb_sender_cpu_clear(skb);
        return dst_output(skb);
 }
 
@@ -541,7 +542,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
        struct sk_buff *frag;
        struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
-       struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+       struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
+                               inet6_sk(skb->sk) : NULL;
        struct ipv6hdr *tmp_hdr;
        struct frag_hdr *fh;
        unsigned int mtu, hlen, left, len;
@@ -1298,7 +1300,8 @@ emsgsize:
        if (((length > mtu) ||
             (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
-           (rt->dst.dev->features & NETIF_F_UFO)) {
+           (rt->dst.dev->features & NETIF_F_UFO) &&
+           (sk->sk_type == SOCK_DGRAM)) {
                err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
                                          hh_len, fragheaderlen,
                                          transhdrlen, mtu, flags, rt);
index 266a264..ddd94ec 100644 (file)
@@ -314,7 +314,7 @@ out:
  *   Create tunnel matching given parameters.
  *
  * Return:
- *   created tunnel or NULL
+ *   created tunnel or error pointer
  **/
 
 static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
@@ -322,7 +322,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
        struct net_device *dev;
        struct ip6_tnl *t;
        char name[IFNAMSIZ];
-       int err;
+       int err = -ENOMEM;
 
        if (p->name[0])
                strlcpy(name, p->name, IFNAMSIZ);
@@ -348,7 +348,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
 failed_free:
        ip6_dev_free(dev);
 failed:
-       return NULL;
+       return ERR_PTR(err);
 }
 
 /**
@@ -362,7 +362,7 @@ failed:
  *   tunnel device is created and registered for use.
  *
  * Return:
- *   matching tunnel or NULL
+ *   matching tunnel or error pointer
  **/
 
 static struct ip6_tnl *ip6_tnl_locate(struct net *net,
@@ -380,13 +380,13 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net,
                if (ipv6_addr_equal(local, &t->parms.laddr) &&
                    ipv6_addr_equal(remote, &t->parms.raddr)) {
                        if (create)
-                               return NULL;
+                               return ERR_PTR(-EEXIST);
 
                        return t;
                }
        }
        if (!create)
-               return NULL;
+               return ERR_PTR(-ENODEV);
        return ip6_tnl_create(net, p);
 }
 
@@ -1420,7 +1420,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        }
                        ip6_tnl_parm_from_user(&p1, &p);
                        t = ip6_tnl_locate(net, &p1, 0);
-                       if (t == NULL)
+                       if (IS_ERR(t))
                                t = netdev_priv(dev);
                } else {
                        memset(&p, 0, sizeof(p));
@@ -1445,7 +1445,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                ip6_tnl_parm_from_user(&p1, &p);
                t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
                if (cmd == SIOCCHGTUNNEL) {
-                       if (t != NULL) {
+                       if (!IS_ERR(t)) {
                                if (t->dev != dev) {
                                        err = -EEXIST;
                                        break;
@@ -1457,14 +1457,15 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        else
                                err = ip6_tnl_update(t, &p1);
                }
-               if (t) {
+               if (!IS_ERR(t)) {
                        err = 0;
                        ip6_tnl_parm_to_user(&p, &t->parms);
                        if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
                                err = -EFAULT;
 
-               } else
-                       err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+               } else {
+                       err = PTR_ERR(t);
+               }
                break;
        case SIOCDELTUNNEL:
                err = -EPERM;
@@ -1478,7 +1479,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        err = -ENOENT;
                        ip6_tnl_parm_from_user(&p1, &p);
                        t = ip6_tnl_locate(net, &p1, 0);
-                       if (t == NULL)
+                       if (IS_ERR(t))
                                break;
                        err = -EPERM;
                        if (t->dev == ip6n->fb_tnl_dev)
@@ -1672,12 +1673,13 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
                           struct nlattr *tb[], struct nlattr *data[])
 {
        struct net *net = dev_net(dev);
-       struct ip6_tnl *nt;
+       struct ip6_tnl *nt, *t;
 
        nt = netdev_priv(dev);
        ip6_tnl_netlink_parms(data, &nt->parms);
 
-       if (ip6_tnl_locate(net, &nt->parms, 0))
+       t = ip6_tnl_locate(net, &nt->parms, 0);
+       if (!IS_ERR(t))
                return -EEXIST;
 
        return ip6_tnl_create2(dev);
@@ -1697,8 +1699,7 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
        ip6_tnl_netlink_parms(data, &p);
 
        t = ip6_tnl_locate(net, &p, 0);
-
-       if (t) {
+       if (!IS_ERR(t)) {
                if (t->dev != dev)
                        return -EEXIST;
        } else
index 34b6826..312e0ff 100644 (file)
@@ -252,7 +252,7 @@ static int __net_init ip6mr_rules_init(struct net *net)
        return 0;
 
 err2:
-       kfree(mrt);
+       ip6mr_free_table(mrt);
 err1:
        fib_rules_unregister(ops);
        return err;
@@ -267,8 +267,8 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
                list_del(&mrt->list);
                ip6mr_free_table(mrt);
        }
-       rtnl_unlock();
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
+       rtnl_unlock();
 }
 #else
 #define ip6mr_for_each_table(mrt, net) \
@@ -336,7 +336,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
 
 static void ip6mr_free_table(struct mr6_table *mrt)
 {
-       del_timer(&mrt->ipmr_expire_timer);
+       del_timer_sync(&mrt->ipmr_expire_timer);
        mroute_clean_tables(mrt);
        kfree(mrt);
 }
index 471ed24..14ecdaf 100644 (file)
@@ -1218,7 +1218,14 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        if (rt)
                rt6_set_expires(rt, jiffies + (HZ * lifetime));
        if (ra_msg->icmph.icmp6_hop_limit) {
-               in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+               /* Only set hop_limit on the interface if it is higher than
+                * the current hop_limit.
+                */
+               if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) {
+                       in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+               } else {
+                       ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n");
+               }
                if (rt)
                        dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
                                       ra_msg->icmph.icmp6_hop_limit);
index e080fbb..bb00c6f 100644 (file)
@@ -298,9 +298,9 @@ static void trace_packet(const struct sk_buff *skb,
                    &chainname, &comment, &rulenum) != 0)
                        break;
 
-       nf_log_packet(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
-                     "TRACE: %s:%s:%s:%u ",
-                     tablename, chainname, comment, rulenum);
+       nf_log_trace(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
+                    "TRACE: %s:%s:%s:%u ",
+                    tablename, chainname, comment, rulenum);
 }
 #endif
 
index bd46f73..a2dfff6 100644 (file)
@@ -102,9 +102,10 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        if (msg->msg_name) {
                DECLARE_SOCKADDR(struct sockaddr_in6 *, u, msg->msg_name);
-               if (msg->msg_namelen < sizeof(struct sockaddr_in6) ||
-                   u->sin6_family != AF_INET6) {
+               if (msg->msg_namelen < sizeof(*u))
                        return -EINVAL;
+               if (u->sin6_family != AF_INET6) {
+                       return -EAFNOSUPPORT;
                }
                if (sk->sk_bound_dev_if &&
                    sk->sk_bound_dev_if != u->sin6_scope_id) {
index 5d46832..1f5e622 100644 (file)
@@ -1411,6 +1411,15 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,
        TCP_SKB_CB(skb)->sacked = 0;
 }
 
+static void tcp_v6_restore_cb(struct sk_buff *skb)
+{
+       /* We need to move header back to the beginning if xfrm6_policy_check()
+        * and tcp_v6_fill_cb() are going to be called again.
+        */
+       memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+               sizeof(struct inet6_skb_parm));
+}
+
 static int tcp_v6_rcv(struct sk_buff *skb)
 {
        const struct tcphdr *th;
@@ -1543,6 +1552,7 @@ do_time_wait:
                        inet_twsk_deschedule(tw, &tcp_death_row);
                        inet_twsk_put(tw);
                        sk = sk2;
+                       tcp_v6_restore_cb(skb);
                        goto process;
                }
                /* Fall through to ACK */
@@ -1551,6 +1561,7 @@ do_time_wait:
                tcp_v6_timewait_ack(sk, skb);
                break;
        case TCP_TW_RST:
+               tcp_v6_restore_cb(skb);
                goto no_tcp_socket;
        case TCP_TW_SUCCESS:
                ;
@@ -1585,7 +1596,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk->sk_state != TCP_TIME_WAIT) {
-                       struct dst_entry *dst = sk->sk_rx_dst;
+                       struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
index ab889bb..be2c0ba 100644 (file)
@@ -112,11 +112,9 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
                fptr->nexthdr = nexthdr;
                fptr->reserved = 0;
-               if (skb_shinfo(skb)->ip6_frag_id)
-                       fptr->identification = skb_shinfo(skb)->ip6_frag_id;
-               else
-                       ipv6_select_ident(fptr,
-                                         (struct rt6_info *)skb_dst(skb));
+               if (!skb_shinfo(skb)->ip6_frag_id)
+                       ipv6_proxy_select_ident(skb);
+               fptr->identification = skb_shinfo(skb)->ip6_frag_id;
 
                /* Fragment the skb. ipv6 header and the remaining fields of the
                 * fragment header are updated in ipv6_gso_segment()
index ca3f29b..010f8bd 100644 (file)
@@ -114,6 +114,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        skb->ignore_df = 1;
+       skb->protocol = htons(ETH_P_IPV6);
 
        return x->outer_mode->output2(x, skb);
 }
@@ -122,7 +123,6 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
 int xfrm6_output_finish(struct sk_buff *skb)
 {
        memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
-       skb->protocol = htons(ETH_P_IPV6);
 
 #ifdef CONFIG_NETFILTER
        IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
index 48bf5a0..8d2d01b 100644 (file)
@@ -200,6 +200,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
 
 #if IS_ENABLED(CONFIG_IPV6_MIP6)
                case IPPROTO_MH:
+                       offset += ipv6_optlen(exthdr);
                        if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
                                struct ip6_mh *mh;
 
index 40695b9..683346d 100644 (file)
@@ -798,7 +798,9 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
        orig_jiffies = jiffies;
 
        /* Set poll time to 200 ms */
-       poll_time = IRDA_MIN(timeout, msecs_to_jiffies(200));
+       poll_time = msecs_to_jiffies(200);
+       if (timeout)
+               poll_time = min_t(unsigned long, timeout, poll_time);
 
        spin_lock_irqsave(&self->spinlock, flags);
        while (self->tx_skb && self->tx_skb->len) {
@@ -811,7 +813,7 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
                        break;
        }
        spin_unlock_irqrestore(&self->spinlock, flags);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
 }
 
 /*
index 3c83a1e..1215693 100644 (file)
@@ -305,7 +305,7 @@ irnet_ctrl_read(irnet_socket *      ap,
 
   /* Put ourselves on the wait queue to be woken up */
   add_wait_queue(&irnet_events.rwait, &wait);
-  current->state = TASK_INTERRUPTIBLE;
+  set_current_state(TASK_INTERRUPTIBLE);
   for(;;)
     {
       /* If there is unread events */
@@ -321,7 +321,7 @@ irnet_ctrl_read(irnet_socket *      ap,
       /* Yield and wait to be woken up */
       schedule();
     }
-  current->state = TASK_RUNNING;
+  __set_current_state(TASK_RUNNING);
   remove_wait_queue(&irnet_events.rwait, &wait);
 
   /* Did we got it ? */
index 2e9953b..53d9311 100644 (file)
@@ -1114,10 +1114,8 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        noblock, &err);
        else
                skb = sock_alloc_send_skb(sk, len, noblock, &err);
-       if (!skb) {
-               err = -ENOMEM;
+       if (!skb)
                goto out;
-       }
        if (iucv->transport == AF_IUCV_TRANS_HIPER)
                skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN);
        if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
index 895348e..a29a504 100644 (file)
@@ -1871,6 +1871,7 @@ static int __init l2tp_init(void)
        l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0);
        if (!l2tp_wq) {
                pr_err("alloc_workqueue failed\n");
+               unregister_pernet_device(&l2tp_net_ops);
                rc = -ENOMEM;
                goto out;
        }
index a48bad4..7702978 100644 (file)
@@ -49,8 +49,6 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
                container_of(h, struct tid_ampdu_rx, rcu_head);
        int i;
 
-       del_timer_sync(&tid_rx->reorder_timer);
-
        for (i = 0; i < tid_rx->buf_size; i++)
                __skb_queue_purge(&tid_rx->reorder_buf[i]);
        kfree(tid_rx->reorder_buf);
@@ -93,6 +91,12 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 
        del_timer_sync(&tid_rx->session_timer);
 
+       /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
+       spin_lock_bh(&tid_rx->reorder_lock);
+       tid_rx->removed = true;
+       spin_unlock_bh(&tid_rx->reorder_lock);
+       del_timer_sync(&tid_rx->reorder_timer);
+
        call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
 }
 
index ff0d2db..5bcd4e5 100644 (file)
@@ -1508,6 +1508,8 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
        if (ieee80211_chanctx_refcount(local, ctx) == 0)
                ieee80211_free_chanctx(local, ctx);
 
+       sdata->radar_required = false;
+
        /* Unreserving may ready an in-place reservation. */
        if (use_reserved_switch)
                ieee80211_vif_use_reserved_switch(local);
@@ -1566,6 +1568,9 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_smps_chanctx(local, ctx);
        ieee80211_recalc_radar_chanctx(local, ctx);
  out:
+       if (ret)
+               sdata->radar_required = false;
+
        mutex_unlock(&local->chanctx_mtx);
        return ret;
 }
index 3afe368..8d53d65 100644 (file)
@@ -58,13 +58,24 @@ struct ieee80211_local;
 #define IEEE80211_UNSET_POWER_LEVEL    INT_MIN
 
 /*
- * Some APs experience problems when working with U-APSD. Decrease the
- * probability of that happening by using legacy mode for all ACs but VO.
- * The AP that caused us trouble was a Cisco 4410N. It ignores our
- * setting, and always treats non-VO ACs as legacy.
+ * Some APs experience problems when working with U-APSD. Decreasing the
+ * probability of that happening by using legacy mode for all ACs but VO isn't
+ * enough.
+ *
+ * Cisco 4410N originally forced us to enable VO by default only because it
+ * treated non-VO ACs as legacy.
+ *
+ * However some APs (notably Netgear R7000) silently reclassify packets to
+ * different ACs. Since u-APSD ACs require trigger frames for frame retrieval
+ * clients would never see some frames (e.g. ARP responses) or would fetch them
+ * accidentally after a long time.
+ *
+ * It makes little sense to enable u-APSD queues by default because it needs
+ * userspace applications to be aware of it to actually take advantage of the
+ * possible additional powersavings. Implicitly depending on driver autotrigger
+ * frame support doesn't make much sense.
  */
-#define IEEE80211_DEFAULT_UAPSD_QUEUES \
-       IEEE80211_WMM_IE_STA_QOSINFO_AC_VO
+#define IEEE80211_DEFAULT_UAPSD_QUEUES 0
 
 #define IEEE80211_DEFAULT_MAX_SP_LEN           \
        IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
@@ -453,6 +464,7 @@ struct ieee80211_if_managed {
        unsigned int flags;
 
        bool csa_waiting_bcn;
+       bool csa_ignored_same_chan;
 
        bool beacon_crc_valid;
        u32 beacon_crc;
index 10ac632..142f66a 100644 (file)
@@ -1150,6 +1150,17 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
+       if (cfg80211_chandef_identical(&csa_ie.chandef,
+                                      &sdata->vif.bss_conf.chandef)) {
+               if (ifmgd->csa_ignored_same_chan)
+                       return;
+               sdata_info(sdata,
+                          "AP %pM tries to chanswitch to same channel, ignore\n",
+                          ifmgd->associated->bssid);
+               ifmgd->csa_ignored_same_chan = true;
+               return;
+       }
+
        mutex_lock(&local->mtx);
        mutex_lock(&local->chanctx_mtx);
        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
@@ -1210,6 +1221,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        sdata->vif.csa_active = true;
        sdata->csa_chandef = csa_ie.chandef;
        sdata->csa_block_tx = csa_ie.mode;
+       ifmgd->csa_ignored_same_chan = false;
 
        if (sdata->csa_block_tx)
                ieee80211_stop_vif_queues(local, sdata,
@@ -2090,6 +2102,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        sdata->vif.csa_active = false;
        ifmgd->csa_waiting_bcn = false;
+       ifmgd->csa_ignored_same_chan = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3204,7 +3217,8 @@ static const u64 care_about_ies =
        (1ULL << WLAN_EID_CHANNEL_SWITCH) |
        (1ULL << WLAN_EID_PWR_CONSTRAINT) |
        (1ULL << WLAN_EID_HT_CAPABILITY) |
-       (1ULL << WLAN_EID_HT_OPERATION);
+       (1ULL << WLAN_EID_HT_OPERATION) |
+       (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN);
 
 static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt, size_t len,
index 7c86a00..ef6e8a6 100644 (file)
@@ -373,7 +373,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                rate++;
                mi->sample_deferred++;
        } else {
-               if (!msr->sample_limit != 0)
+               if (!msr->sample_limit)
                        return;
 
                mi->sample_packets++;
index 1101563..1eb730b 100644 (file)
@@ -873,9 +873,10 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
 
  set_release_timer:
 
-               mod_timer(&tid_agg_rx->reorder_timer,
-                         tid_agg_rx->reorder_time[j] + 1 +
-                         HT_RX_REORDER_BUF_TIMEOUT);
+               if (!tid_agg_rx->removed)
+                       mod_timer(&tid_agg_rx->reorder_timer,
+                                 tid_agg_rx->reorder_time[j] + 1 +
+                                 HT_RX_REORDER_BUF_TIMEOUT);
        } else {
                del_timer(&tid_agg_rx->reorder_timer);
        }
@@ -2214,6 +2215,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        hdr = (struct ieee80211_hdr *) skb->data;
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
 
+       if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
+               return RX_DROP_MONITOR;
+
        /* frame is in RMC, don't forward */
        if (ieee80211_is_data(hdr->frame_control) &&
            is_multicast_ether_addr(hdr->addr1) &&
index 925e68f..fb0fc13 100644 (file)
@@ -175,6 +175,7 @@ struct tid_ampdu_tx {
  * @reorder_lock: serializes access to reorder buffer, see below.
  * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
  *     and ssn.
+ * @removed: this session is removed (but might have been found due to RCU)
  *
  * This structure's lifetime is managed by RCU, assignments to
  * the array holding it must hold the aggregation mutex.
@@ -199,6 +200,7 @@ struct tid_ampdu_rx {
        u16 timeout;
        u8 dialog_token;
        bool auto_seq;
+       bool removed;
 };
 
 /**
index 88a18ff..07bd8db 100644 (file)
@@ -566,6 +566,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
                if (tx->sdata->control_port_no_encrypt)
                        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
                info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
+               info->flags |= IEEE80211_TX_CTL_USE_MINRATE;
        }
 
        return TX_CONTINUE;
index 8428f4a..747bdcf 100644 (file)
@@ -3178,7 +3178,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
                wdev_iter = &sdata_iter->wdev;
 
                if (sdata_iter == sdata ||
-                   rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
+                   !ieee80211_sdata_running(sdata_iter) ||
                    local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
                        continue;
 
index e557590..ed99448 100644 (file)
@@ -3402,7 +3402,7 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
                if (udest.af == 0)
                        udest.af = svc->af;
 
-               if (udest.af != svc->af) {
+               if (udest.af != svc->af && cmd != IPVS_CMD_DEL_DEST) {
                        /* The synchronization protocol is incompatible
                         * with mixed family services
                         */
index c47ffd7..d93ceeb 100644 (file)
@@ -896,6 +896,8 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param,
                        IP_VS_DBG(2, "BACKUP, add new conn. failed\n");
                        return;
                }
+               if (!(flags & IP_VS_CONN_F_TEMPLATE))
+                       kfree(param->pe_data);
        }
 
        if (opt)
@@ -1169,6 +1171,7 @@ static inline int ip_vs_proc_sync_conn(struct net *net, __u8 *p, __u8 *msg_end)
                                (opt_flags & IPVS_OPT_F_SEQ_DATA ? &opt : NULL)
                                );
 #endif
+       ip_vs_pe_put(param.pe);
        return 0;
        /* Error exit */
 out:
index 0d8448f..675d12c 100644 (file)
@@ -212,6 +212,30 @@ void nf_log_packet(struct net *net,
 }
 EXPORT_SYMBOL(nf_log_packet);
 
+void nf_log_trace(struct net *net,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *loginfo, const char *fmt, ...)
+{
+       va_list args;
+       char prefix[NF_LOG_PREFIXLEN];
+       const struct nf_logger *logger;
+
+       rcu_read_lock();
+       logger = rcu_dereference(net->nf.nf_loggers[pf]);
+       if (logger) {
+               va_start(args, fmt);
+               vsnprintf(prefix, sizeof(prefix), fmt, args);
+               va_end(args);
+               logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(nf_log_trace);
+
 #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
 
 struct nf_log_buf {
index 199fd0f..ac1a952 100644 (file)
@@ -227,7 +227,7 @@ nft_rule_deactivate_next(struct net *net, struct nft_rule *rule)
 
 static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
 {
-       rule->genmask = 0;
+       rule->genmask &= ~(1 << gencursor_next(net));
 }
 
 static int
@@ -1225,7 +1225,10 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 
        if (nla[NFTA_CHAIN_POLICY]) {
                if ((chain != NULL &&
-                   !(chain->flags & NFT_BASE_CHAIN)) ||
+                   !(chain->flags & NFT_BASE_CHAIN)))
+                       return -EOPNOTSUPP;
+
+               if (chain == NULL &&
                    nla[NFTA_CHAIN_HOOK] == NULL)
                        return -EOPNOTSUPP;
 
@@ -1711,9 +1714,12 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
        }
        nla_nest_end(skb, list);
 
-       if (rule->ulen &&
-           nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule)))
-               goto nla_put_failure;
+       if (rule->udata) {
+               struct nft_userdata *udata = nft_userdata(rule);
+               if (nla_put(skb, NFTA_RULE_USERDATA, udata->len + 1,
+                           udata->data) < 0)
+                       goto nla_put_failure;
+       }
 
        nlmsg_end(skb, nlh);
        return 0;
@@ -1896,11 +1902,12 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
        struct nft_table *table;
        struct nft_chain *chain;
        struct nft_rule *rule, *old_rule = NULL;
+       struct nft_userdata *udata;
        struct nft_trans *trans = NULL;
        struct nft_expr *expr;
        struct nft_ctx ctx;
        struct nlattr *tmp;
-       unsigned int size, i, n, ulen = 0;
+       unsigned int size, i, n, ulen = 0, usize = 0;
        int err, rem;
        bool create;
        u64 handle, pos_handle;
@@ -1968,12 +1975,19 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
                        n++;
                }
        }
+       /* Check for overflow of dlen field */
+       err = -EFBIG;
+       if (size >= 1 << 12)
+               goto err1;
 
-       if (nla[NFTA_RULE_USERDATA])
+       if (nla[NFTA_RULE_USERDATA]) {
                ulen = nla_len(nla[NFTA_RULE_USERDATA]);
+               if (ulen > 0)
+                       usize = sizeof(struct nft_userdata) + ulen;
+       }
 
        err = -ENOMEM;
-       rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL);
+       rule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL);
        if (rule == NULL)
                goto err1;
 
@@ -1981,10 +1995,13 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
        rule->handle = handle;
        rule->dlen   = size;
-       rule->ulen   = ulen;
+       rule->udata  = ulen ? 1 : 0;
 
-       if (ulen)
-               nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen);
+       if (ulen) {
+               udata = nft_userdata(rule);
+               udata->len = ulen - 1;
+               nla_memcpy(udata->data, nla[NFTA_RULE_USERDATA], ulen);
+       }
 
        expr = nft_expr_first(rule);
        for (i = 0; i < n; i++) {
@@ -2031,12 +2048,6 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
 err3:
        list_del_rcu(&rule->list);
-       if (trans) {
-               list_del_rcu(&nft_trans_rule(trans)->list);
-               nft_rule_clear(net, nft_trans_rule(trans));
-               nft_trans_destroy(trans);
-               chain->use++;
-       }
 err2:
        nf_tables_rule_destroy(&ctx, rule);
 err1:
@@ -3612,12 +3623,11 @@ static int nf_tables_commit(struct sk_buff *skb)
                                                 &te->elem,
                                                 NFT_MSG_DELSETELEM, 0);
                        te->set->ops->get(te->set, &te->elem);
-                       te->set->ops->remove(te->set, &te->elem);
                        nft_data_uninit(&te->elem.key, NFT_DATA_VALUE);
-                       if (te->elem.flags & NFT_SET_MAP) {
-                               nft_data_uninit(&te->elem.data,
-                                               te->set->dtype);
-                       }
+                       if (te->set->flags & NFT_SET_MAP &&
+                           !(te->elem.flags & NFT_SET_ELEM_INTERVAL_END))
+                               nft_data_uninit(&te->elem.data, te->set->dtype);
+                       te->set->ops->remove(te->set, &te->elem);
                        nft_trans_destroy(trans);
                        break;
                }
@@ -3658,7 +3668,7 @@ static int nf_tables_abort(struct sk_buff *skb)
 {
        struct net *net = sock_net(skb->sk);
        struct nft_trans *trans, *next;
-       struct nft_set *set;
+       struct nft_trans_elem *te;
 
        list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
                switch (trans->msg_type) {
@@ -3719,9 +3729,13 @@ static int nf_tables_abort(struct sk_buff *skb)
                        break;
                case NFT_MSG_NEWSETELEM:
                        nft_trans_elem_set(trans)->nelems--;
-                       set = nft_trans_elem_set(trans);
-                       set->ops->get(set, &nft_trans_elem(trans));
-                       set->ops->remove(set, &nft_trans_elem(trans));
+                       te = (struct nft_trans_elem *)trans->data;
+                       te->set->ops->get(te->set, &te->elem);
+                       nft_data_uninit(&te->elem.key, NFT_DATA_VALUE);
+                       if (te->set->flags & NFT_SET_MAP &&
+                           !(te->elem.flags & NFT_SET_ELEM_INTERVAL_END))
+                               nft_data_uninit(&te->elem.data, te->set->dtype);
+                       te->set->ops->remove(te->set, &te->elem);
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELSETELEM:
index 3b90eb2..2d298dc 100644 (file)
@@ -94,10 +94,10 @@ static void nft_trace_packet(const struct nft_pktinfo *pkt,
 {
        struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
 
-       nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
-                     pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
-                     chain->table->name, chain->name, comments[type],
-                     rulenum);
+       nf_log_trace(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
+                    pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
+                    chain->table->name, chain->name, comments[type],
+                    rulenum);
 }
 
 unsigned int
index a5599fc..54330fb 100644 (file)
@@ -77,6 +77,9 @@ nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
        if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
                return -EINVAL;
 
+       /* Not all fields are initialized so first zero the tuple */
+       memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
+
        tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
        tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
 
index c598f74..65f3e2b 100644 (file)
@@ -123,7 +123,7 @@ static void
 nft_target_set_tgchk_param(struct xt_tgchk_param *par,
                           const struct nft_ctx *ctx,
                           struct xt_target *target, void *info,
-                          union nft_entry *entry, u8 proto, bool inv)
+                          union nft_entry *entry, u16 proto, bool inv)
 {
        par->net        = ctx->net;
        par->table      = ctx->table->name;
@@ -133,11 +133,14 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
                break;
        case AF_INET6:
+               if (proto)
+                       entry->e6.ipv6.flags |= IP6T_F_PROTO;
+
                entry->e6.ipv6.proto = proto;
                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
                break;
        case NFPROTO_BRIDGE:
-               entry->ebt.ethproto = proto;
+               entry->ebt.ethproto = (__force __be16)proto;
                entry->ebt.invflags = inv ? EBT_IPROTO : 0;
                break;
        }
@@ -171,7 +174,7 @@ static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1]
        [NFTA_RULE_COMPAT_FLAGS]        = { .type = NLA_U32 },
 };
 
-static int nft_parse_compat(const struct nlattr *attr, u8 *proto, bool *inv)
+static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)
 {
        struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
        u32 flags;
@@ -203,7 +206,7 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        struct xt_target *target = expr->ops->data;
        struct xt_tgchk_param par;
        size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
-       u8 proto = 0;
+       u16 proto = 0;
        bool inv = false;
        union nft_entry e = {};
        int ret;
@@ -334,7 +337,7 @@ static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
 static void
 nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
                          struct xt_match *match, void *info,
-                         union nft_entry *entry, u8 proto, bool inv)
+                         union nft_entry *entry, u16 proto, bool inv)
 {
        par->net        = ctx->net;
        par->table      = ctx->table->name;
@@ -344,11 +347,14 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
                break;
        case AF_INET6:
+               if (proto)
+                       entry->e6.ipv6.flags |= IP6T_F_PROTO;
+
                entry->e6.ipv6.proto = proto;
                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
                break;
        case NFPROTO_BRIDGE:
-               entry->ebt.ethproto = proto;
+               entry->ebt.ethproto = (__force __be16)proto;
                entry->ebt.invflags = inv ? EBT_IPROTO : 0;
                break;
        }
@@ -385,7 +391,7 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        struct xt_match *match = expr->ops->data;
        struct xt_mtchk_param par;
        size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
-       u8 proto = 0;
+       u16 proto = 0;
        bool inv = false;
        union nft_entry e = {};
        int ret;
@@ -625,8 +631,12 @@ nft_match_select_ops(const struct nft_ctx *ctx,
                struct xt_match *match = nft_match->ops.data;
 
                if (strcmp(match->name, mt_name) == 0 &&
-                   match->revision == rev && match->family == family)
+                   match->revision == rev && match->family == family) {
+                       if (!try_module_get(match->me))
+                               return ERR_PTR(-ENOENT);
+
                        return &nft_match->ops;
+               }
        }
 
        match = xt_request_find_match(family, mt_name, rev);
@@ -695,8 +705,12 @@ nft_target_select_ops(const struct nft_ctx *ctx,
                struct xt_target *target = nft_target->ops.data;
 
                if (strcmp(target->name, tg_name) == 0 &&
-                   target->revision == rev && target->family == family)
+                   target->revision == rev && target->family == family) {
+                       if (!try_module_get(target->me))
+                               return ERR_PTR(-ENOENT);
+
                        return &nft_target->ops;
+               }
        }
 
        target = xt_request_find_target(family, tg_name, rev);
index 61e6c40..37c15e6 100644 (file)
@@ -153,6 +153,8 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
                                iter->err = err;
                                goto out;
                        }
+
+                       continue;
                }
 
                if (iter->count < iter->skip)
@@ -192,8 +194,6 @@ static int nft_hash_init(const struct nft_set *set,
                .key_offset = offsetof(struct nft_hash_elem, key),
                .key_len = set->klen,
                .hashfn = jhash,
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        return rhashtable_init(priv, &params);
index ef8a926..50e1e5a 100644 (file)
@@ -513,8 +513,8 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct ip6t_ip6 *i = par->entryinfo;
 
-       if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
-           && !(i->flags & IP6T_INV_PROTO))
+       if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) &&
+           !(i->invflags & IP6T_INV_PROTO))
                return 0;
 
        pr_info("Can be used only in combination with "
index 30dbe34..45e1b30 100644 (file)
@@ -378,12 +378,11 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
        mutex_lock(&recent_mutex);
        t = recent_table_lookup(recent_net, info->name);
        if (t != NULL) {
-               if (info->hit_count > t->nstamps_max_mask) {
-                       pr_info("hitcount (%u) is larger than packets to be remembered (%u) for table %s\n",
-                               info->hit_count, t->nstamps_max_mask + 1,
-                               info->name);
-                       ret = -EINVAL;
-                       goto out;
+               if (nstamp_mask > t->nstamps_max_mask) {
+                       spin_lock_bh(&recent_lock);
+                       recent_table_flush(t);
+                       t->nstamps_max_mask = nstamp_mask;
+                       spin_unlock_bh(&recent_lock);
                }
 
                t->refcnt++;
index 1ba6793..13332db 100644 (file)
@@ -243,12 +243,13 @@ static int
 extract_icmp6_fields(const struct sk_buff *skb,
                     unsigned int outside_hdrlen,
                     int *protocol,
-                    struct in6_addr **raddr,
-                    struct in6_addr **laddr,
+                    const struct in6_addr **raddr,
+                    const struct in6_addr **laddr,
                     __be16 *rport,
-                    __be16 *lport)
+                    __be16 *lport,
+                    struct ipv6hdr *ipv6_var)
 {
-       struct ipv6hdr *inside_iph, _inside_iph;
+       const struct ipv6hdr *inside_iph;
        struct icmp6hdr *icmph, _icmph;
        __be16 *ports, _ports[2];
        u8 inside_nexthdr;
@@ -263,12 +264,14 @@ extract_icmp6_fields(const struct sk_buff *skb,
        if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
                return 1;
 
-       inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph), &_inside_iph);
+       inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph),
+                                       sizeof(*ipv6_var), ipv6_var);
        if (inside_iph == NULL)
                return 1;
        inside_nexthdr = inside_iph->nexthdr;
 
-       inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph),
+       inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) +
+                                             sizeof(*ipv6_var),
                                         &inside_nexthdr, &inside_fragoff);
        if (inside_hdrlen < 0)
                return 1; /* hjm: Packet has no/incomplete transport layer headers. */
@@ -315,10 +318,10 @@ xt_socket_get_sock_v6(struct net *net, const u8 protocol,
 static bool
 socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 {
-       struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct ipv6hdr ipv6_var, *iph = ipv6_hdr(skb);
        struct udphdr _hdr, *hp = NULL;
        struct sock *sk = skb->sk;
-       struct in6_addr *daddr = NULL, *saddr = NULL;
+       const struct in6_addr *daddr = NULL, *saddr = NULL;
        __be16 uninitialized_var(dport), uninitialized_var(sport);
        int thoff = 0, uninitialized_var(tproto);
        const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
@@ -342,7 +345,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 
        } else if (tproto == IPPROTO_ICMPV6) {
                if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
-                                        &sport, &dport))
+                                        &sport, &dport, &ipv6_var))
                        return false;
        } else {
                return false;
index 2702673..05919bf 100644 (file)
@@ -3126,8 +3126,6 @@ static int __init netlink_proto_init(void)
                .key_len = sizeof(u32), /* portid */
                .hashfn = jhash,
                .max_shift = 16, /* 64K */
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        if (err != 0)
index ae5e77c..5bae724 100644 (file)
@@ -2194,14 +2194,55 @@ static int __net_init ovs_init_net(struct net *net)
        return 0;
 }
 
-static void __net_exit ovs_exit_net(struct net *net)
+static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
+                                           struct list_head *head)
 {
-       struct datapath *dp, *dp_next;
        struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
+       struct datapath *dp;
+
+       list_for_each_entry(dp, &ovs_net->dps, list_node) {
+               int i;
+
+               for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
+                       struct vport *vport;
+
+                       hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) {
+                               struct netdev_vport *netdev_vport;
+
+                               if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL)
+                                       continue;
+
+                               netdev_vport = netdev_vport_priv(vport);
+                               if (dev_net(netdev_vport->dev) == dnet)
+                                       list_add(&vport->detach_list, head);
+                       }
+               }
+       }
+}
+
+static void __net_exit ovs_exit_net(struct net *dnet)
+{
+       struct datapath *dp, *dp_next;
+       struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id);
+       struct vport *vport, *vport_next;
+       struct net *net;
+       LIST_HEAD(head);
 
        ovs_lock();
        list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
                __dp_destroy(dp);
+
+       rtnl_lock();
+       for_each_net(net)
+               list_vports_from_net(net, dnet, &head);
+       rtnl_unlock();
+
+       /* Detach all vports from given namespace. */
+       list_for_each_entry_safe(vport, vport_next, &head, detach_list) {
+               list_del(&vport->detach_list);
+               ovs_dp_detach_port(vport);
+       }
+
        ovs_unlock();
 
        cancel_work_sync(&ovs_net->dp_notify_work);
index 216f20b..22b18c1 100644 (file)
@@ -2253,14 +2253,20 @@ static int masked_set_action_to_set_action_attr(const struct nlattr *a,
                                                struct sk_buff *skb)
 {
        const struct nlattr *ovs_key = nla_data(a);
+       struct nlattr *nla;
        size_t key_len = nla_len(ovs_key) / 2;
 
        /* Revert the conversion we did from a non-masked set action to
         * masked set action.
         */
-       if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a) - key_len, ovs_key))
+       nla = nla_nest_start(skb, OVS_ACTION_ATTR_SET);
+       if (!nla)
                return -EMSGSIZE;
 
+       if (nla_put(skb, nla_type(ovs_key), key_len, nla_data(ovs_key)))
+               return -EMSGSIZE;
+
+       nla_nest_end(skb, nla);
        return 0;
 }
 
index ec2954f..067a3ff 100644 (file)
@@ -274,10 +274,8 @@ void ovs_vport_del(struct vport *vport)
        ASSERT_OVSL();
 
        hlist_del_rcu(&vport->hash_node);
-
-       vport->ops->destroy(vport);
-
        module_put(vport->ops->owner);
+       vport->ops->destroy(vport);
 }
 
 /**
index f8ae295..bc85331 100644 (file)
@@ -103,6 +103,7 @@ struct vport_portids {
  * @ops: Class structure.
  * @percpu_stats: Points to per-CPU statistics used and maintained by vport
  * @err_stats: Points to error statistics used and maintained by vport
+ * @detach_list: list used for detaching vport in net-exit call.
  */
 struct vport {
        struct rcu_head rcu;
@@ -117,6 +118,7 @@ struct vport {
        struct pcpu_sw_netstats __percpu *percpu_stats;
 
        struct vport_err_stats err_stats;
+       struct list_head detach_list;
 };
 
 /**
index 9c28cec..f8db706 100644 (file)
@@ -698,6 +698,10 @@ static void prb_retire_rx_blk_timer_expired(unsigned long data)
 
        if (pkc->last_kactive_blk_num == pkc->kactive_blk_num) {
                if (!frozen) {
+                       if (!BLOCK_NUM_PKTS(pbd)) {
+                               /* An empty block. Just refresh the timer. */
+                               goto refresh_timer;
+                       }
                        prb_retire_current_block(pkc, po, TP_STATUS_BLK_TMO);
                        if (!prb_dispatch_next_block(pkc, po))
                                goto refresh_timer;
@@ -798,7 +802,11 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
                h1->ts_last_pkt.ts_sec = last_pkt->tp_sec;
                h1->ts_last_pkt.ts_nsec = last_pkt->tp_nsec;
        } else {
-               /* Ok, we tmo'd - so get the current time */
+               /* Ok, we tmo'd - so get the current time.
+                *
+                * It shouldn't really happen as we don't close empty
+                * blocks. See prb_retire_rx_blk_timer_expired().
+                */
                struct timespec ts;
                getnstimeofday(&ts);
                h1->ts_last_pkt.ts_sec = ts.tv_sec;
@@ -1349,14 +1357,14 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
                return 0;
        }
 
+       if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
+               skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
+               if (!skb)
+                       return 0;
+       }
        switch (f->type) {
        case PACKET_FANOUT_HASH:
        default:
-               if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
-                       skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
-                       if (!skb)
-                               return 0;
-               }
                idx = fanout_demux_hash(f, skb, num);
                break;
        case PACKET_FANOUT_LB:
@@ -3115,11 +3123,18 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
        return 0;
 }
 
-static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what)
+static void packet_dev_mclist_delete(struct net_device *dev,
+                                    struct packet_mclist **mlp)
 {
-       for ( ; i; i = i->next) {
-               if (i->ifindex == dev->ifindex)
-                       packet_dev_mc(dev, i, what);
+       struct packet_mclist *ml;
+
+       while ((ml = *mlp) != NULL) {
+               if (ml->ifindex == dev->ifindex) {
+                       packet_dev_mc(dev, ml, -1);
+                       *mlp = ml->next;
+                       kfree(ml);
+               } else
+                       mlp = &ml->next;
        }
 }
 
@@ -3196,12 +3211,11 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq)
                                        packet_dev_mc(dev, ml, -1);
                                kfree(ml);
                        }
-                       rtnl_unlock();
-                       return 0;
+                       break;
                }
        }
        rtnl_unlock();
-       return -EADDRNOTAVAIL;
+       return 0;
 }
 
 static void packet_flush_mclist(struct sock *sk)
@@ -3551,7 +3565,7 @@ static int packet_notifier(struct notifier_block *this,
                switch (msg) {
                case NETDEV_UNREGISTER:
                        if (po->mclist)
-                               packet_dev_mclist(dev, po->mclist, -1);
+                               packet_dev_mclist_delete(dev, &po->mclist);
                        /* fallthrough */
 
                case NETDEV_DOWN:
index a817705..dba8d08 100644 (file)
@@ -88,7 +88,9 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
                        int *unpinned);
 static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
 
-static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id)
+static int rds_iw_get_device(struct sockaddr_in *src, struct sockaddr_in *dst,
+                            struct rds_iw_device **rds_iwdev,
+                            struct rdma_cm_id **cm_id)
 {
        struct rds_iw_device *iwdev;
        struct rds_iw_cm_id *i_cm_id;
@@ -112,15 +114,15 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
                                src_addr->sin_port,
                                dst_addr->sin_addr.s_addr,
                                dst_addr->sin_port,
-                               rs->rs_bound_addr,
-                               rs->rs_bound_port,
-                               rs->rs_conn_addr,
-                               rs->rs_conn_port);
+                               src->sin_addr.s_addr,
+                               src->sin_port,
+                               dst->sin_addr.s_addr,
+                               dst->sin_port);
 #ifdef WORKING_TUPLE_DETECTION
-                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr &&
-                           src_addr->sin_port == rs->rs_bound_port &&
-                           dst_addr->sin_addr.s_addr == rs->rs_conn_addr &&
-                           dst_addr->sin_port == rs->rs_conn_port) {
+                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr &&
+                           src_addr->sin_port == src->sin_port &&
+                           dst_addr->sin_addr.s_addr == dst->sin_addr.s_addr &&
+                           dst_addr->sin_port == dst->sin_port) {
 #else
                        /* FIXME - needs to compare the local and remote
                         * ipaddr/port tuple, but the ipaddr is the only
@@ -128,7 +130,7 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
                         * zero'ed.  It doesn't appear to be properly populated
                         * during connection setup...
                         */
-                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr) {
+                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr) {
 #endif
                                spin_unlock_irq(&iwdev->spinlock);
                                *rds_iwdev = iwdev;
@@ -180,19 +182,13 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i
 {
        struct sockaddr_in *src_addr, *dst_addr;
        struct rds_iw_device *rds_iwdev_old;
-       struct rds_sock rs;
        struct rdma_cm_id *pcm_id;
        int rc;
 
        src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr;
        dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr;
 
-       rs.rs_bound_addr = src_addr->sin_addr.s_addr;
-       rs.rs_bound_port = src_addr->sin_port;
-       rs.rs_conn_addr = dst_addr->sin_addr.s_addr;
-       rs.rs_conn_port = dst_addr->sin_port;
-
-       rc = rds_iw_get_device(&rs, &rds_iwdev_old, &pcm_id);
+       rc = rds_iw_get_device(src_addr, dst_addr, &rds_iwdev_old, &pcm_id);
        if (rc)
                rds_iw_remove_cm_id(rds_iwdev, cm_id);
 
@@ -598,9 +594,17 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
        struct rds_iw_device *rds_iwdev;
        struct rds_iw_mr *ibmr = NULL;
        struct rdma_cm_id *cm_id;
+       struct sockaddr_in src = {
+               .sin_addr.s_addr = rs->rs_bound_addr,
+               .sin_port = rs->rs_bound_port,
+       };
+       struct sockaddr_in dst = {
+               .sin_addr.s_addr = rs->rs_conn_addr,
+               .sin_port = rs->rs_conn_port,
+       };
        int ret;
 
-       ret = rds_iw_get_device(rs, &rds_iwdev, &cm_id);
+       ret = rds_iw_get_device(&src, &dst, &rds_iwdev, &cm_id);
        if (ret || !cm_id) {
                ret = -ENODEV;
                goto out;
index c6be17a..e0547f5 100644 (file)
@@ -218,7 +218,8 @@ static void rxrpc_resend(struct rxrpc_call *call)
        struct rxrpc_header *hdr;
        struct sk_buff *txb;
        unsigned long *p_txb, resend_at;
-       int loop, stop;
+       bool stop;
+       int loop;
        u8 resend;
 
        _enter("{%d,%d,%d,%d},",
@@ -226,7 +227,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
               atomic_read(&call->sequence),
               CIRC_CNT(call->acks_head, call->acks_tail, call->acks_winsz));
 
-       stop = 0;
+       stop = false;
        resend = 0;
        resend_at = 0;
 
@@ -255,11 +256,11 @@ static void rxrpc_resend(struct rxrpc_call *call)
                        _proto("Tx DATA %%%u { #%d }",
                               ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
                        if (rxrpc_send_packet(call->conn->trans, txb) < 0) {
-                               stop = 0;
+                               stop = true;
                                sp->resend_at = jiffies + 3;
                        } else {
                                sp->resend_at =
-                                       jiffies + rxrpc_resend_timeout * HZ;
+                                       jiffies + rxrpc_resend_timeout;
                        }
                }
 
index 5394b6b..0610efa 100644 (file)
@@ -42,7 +42,8 @@ void rxrpc_UDP_error_report(struct sock *sk)
                _leave("UDP socket errqueue empty");
                return;
        }
-       if (!skb->len) {
+       serr = SKB_EXT_ERR(skb);
+       if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
                _leave("UDP empty message");
                kfree_skb(skb);
                return;
@@ -50,7 +51,6 @@ void rxrpc_UDP_error_report(struct sock *sk)
 
        rxrpc_new_skb(skb);
 
-       serr = SKB_EXT_ERR(skb);
        addr = *(__be32 *)(skb_network_header(skb) + serr->addr_offset);
        port = serr->port;
 
index 4575485..19a5606 100644 (file)
@@ -87,7 +87,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (!skb) {
                        /* nothing remains on the queue */
                        if (copied &&
-                           (msg->msg_flags & MSG_PEEK || timeo == 0))
+                           (flags & MSG_PEEK || timeo == 0))
                                goto out;
 
                        /* wait for a message to turn up */
index 82c5d7f..5f6288f 100644 (file)
@@ -25,21 +25,41 @@ static int tcf_bpf(struct sk_buff *skb, const struct tc_action *a,
                   struct tcf_result *res)
 {
        struct tcf_bpf *b = a->priv;
-       int action;
-       int filter_res;
+       int action, filter_res;
 
        spin_lock(&b->tcf_lock);
+
        b->tcf_tm.lastuse = jiffies;
        bstats_update(&b->tcf_bstats, skb);
-       action = b->tcf_action;
 
        filter_res = BPF_PROG_RUN(b->filter, skb);
-       if (filter_res == 0) {
-               /* Return code 0 from the BPF program
-                * is being interpreted as a drop here.
-                */
-               action = TC_ACT_SHOT;
+
+       /* A BPF program may overwrite the default action opcode.
+        * Similarly as in cls_bpf, if filter_res == -1 we use the
+        * default action specified from tc.
+        *
+        * In case a different well-known TC_ACT opcode has been
+        * returned, it will overwrite the default one.
+        *
+        * For everything else that is unkown, TC_ACT_UNSPEC is
+        * returned.
+        */
+       switch (filter_res) {
+       case TC_ACT_PIPE:
+       case TC_ACT_RECLASSIFY:
+       case TC_ACT_OK:
+               action = filter_res;
+               break;
+       case TC_ACT_SHOT:
+               action = filter_res;
                b->tcf_qstats.drops++;
+               break;
+       case TC_ACT_UNSPEC:
+               action = b->tcf_action;
+               break;
+       default:
+               action = TC_ACT_UNSPEC;
+               break;
        }
 
        spin_unlock(&b->tcf_lock);
index 09487af..95fdf4e 100644 (file)
@@ -78,8 +78,11 @@ struct tc_u_hnode {
        struct tc_u_common      *tp_c;
        int                     refcnt;
        unsigned int            divisor;
-       struct tc_u_knode __rcu *ht[1];
        struct rcu_head         rcu;
+       /* The 'ht' field MUST be the last field in structure to allow for
+        * more entries allocated at end of structure.
+        */
+       struct tc_u_knode __rcu *ht[1];
 };
 
 struct tc_u_common {
index 6742200..fbb7ebf 100644 (file)
@@ -228,6 +228,7 @@ static int tcf_em_validate(struct tcf_proto *tp,
                                 * to replay the request.
                                 */
                                module_put(em->ops->owner);
+                               em->ops = NULL;
                                err = -EAGAIN;
                        }
 #endif
index bbedbfc..245330c 100644 (file)
@@ -1702,6 +1702,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
 
        if (len > INT_MAX)
                len = INT_MAX;
+       if (unlikely(!access_ok(VERIFY_READ, buff, len)))
+               return -EFAULT;
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
@@ -1760,6 +1762,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
 
        if (size > INT_MAX)
                size = INT_MAX;
+       if (unlikely(!access_ok(VERIFY_WRITE, ubuf, size)))
+               return -EFAULT;
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
index abbb7dc..59eeed4 100644 (file)
@@ -217,6 +217,8 @@ static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg)
 
        for (i = 0; i < arg->npages && arg->pages[i]; i++)
                __free_page(arg->pages[i]);
+
+       kfree(arg->pages);
 }
 
 static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
index 224a82f..1095be9 100644 (file)
@@ -463,6 +463,8 @@ static int rsc_parse(struct cache_detail *cd,
                /* number of additional gid's */
                if (get_int(&mesg, &N))
                        goto out;
+               if (N < 0 || N > NGROUPS_MAX)
+                       goto out;
                status = -ENOMEM;
                rsci.cred.cr_group_info = groups_alloc(N);
                if (rsci.cred.cr_group_info == NULL)
index 33fb105..5199bb1 100644 (file)
@@ -921,7 +921,7 @@ static unsigned int cache_poll(struct file *filp, poll_table *wait,
        poll_wait(filp, &queue_wait, wait);
 
        /* alway allow write */
-       mask = POLL_OUT | POLLWRNORM;
+       mask = POLLOUT | POLLWRNORM;
 
        if (!rp)
                return mask;
index 612aa73..e6ce151 100644 (file)
@@ -303,9 +303,7 @@ static int rpc_client_register(struct rpc_clnt *clnt,
        struct super_block *pipefs_sb;
        int err;
 
-       err = rpc_clnt_debugfs_register(clnt);
-       if (err)
-               return err;
+       rpc_clnt_debugfs_register(clnt);
 
        pipefs_sb = rpc_get_sb_net(net);
        if (pipefs_sb) {
index e811f39..82962f7 100644 (file)
@@ -129,48 +129,52 @@ static const struct file_operations tasks_fops = {
        .release        = tasks_release,
 };
 
-int
+void
 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
 {
-       int len, err;
+       int len;
        char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
+       struct rpc_xprt *xprt;
 
        /* Already registered? */
-       if (clnt->cl_debugfs)
-               return 0;
+       if (clnt->cl_debugfs || !rpc_clnt_dir)
+               return;
 
        len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
        if (len >= sizeof(name))
-               return -EINVAL;
+               return;
 
        /* make the per-client dir */
        clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
        if (!clnt->cl_debugfs)
-               return -ENOMEM;
+               return;
 
        /* make tasks file */
-       err = -ENOMEM;
        if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs,
                                 clnt, &tasks_fops))
                goto out_err;
 
-       err = -EINVAL;
        rcu_read_lock();
+       xprt = rcu_dereference(clnt->cl_xprt);
+       /* no "debugfs" dentry? Don't bother with the symlink. */
+       if (!xprt->debugfs) {
+               rcu_read_unlock();
+               return;
+       }
        len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
-                       rcu_dereference(clnt->cl_xprt)->debugfs->d_name.name);
+                       xprt->debugfs->d_name.name);
        rcu_read_unlock();
+
        if (len >= sizeof(name))
                goto out_err;
 
-       err = -ENOMEM;
        if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name))
                goto out_err;
 
-       return 0;
+       return;
 out_err:
        debugfs_remove_recursive(clnt->cl_debugfs);
        clnt->cl_debugfs = NULL;
-       return err;
 }
 
 void
@@ -226,33 +230,33 @@ static const struct file_operations xprt_info_fops = {
        .release        = xprt_info_release,
 };
 
-int
+void
 rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
 {
        int len, id;
        static atomic_t cur_id;
        char            name[9]; /* 8 hex digits + NULL term */
 
+       if (!rpc_xprt_dir)
+               return;
+
        id = (unsigned int)atomic_inc_return(&cur_id);
 
        len = snprintf(name, sizeof(name), "%x", id);
        if (len >= sizeof(name))
-               return -EINVAL;
+               return;
 
        /* make the per-client dir */
        xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir);
        if (!xprt->debugfs)
-               return -ENOMEM;
+               return;
 
        /* make tasks file */
        if (!debugfs_create_file("info", S_IFREG | S_IRUSR, xprt->debugfs,
                                 xprt, &xprt_info_fops)) {
                debugfs_remove_recursive(xprt->debugfs);
                xprt->debugfs = NULL;
-               return -ENOMEM;
        }
-
-       return 0;
 }
 
 void
@@ -266,14 +270,17 @@ void __exit
 sunrpc_debugfs_exit(void)
 {
        debugfs_remove_recursive(topdir);
+       topdir = NULL;
+       rpc_clnt_dir = NULL;
+       rpc_xprt_dir = NULL;
 }
 
-int __init
+void __init
 sunrpc_debugfs_init(void)
 {
        topdir = debugfs_create_dir("sunrpc", NULL);
        if (!topdir)
-               goto out;
+               return;
 
        rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
        if (!rpc_clnt_dir)
@@ -283,10 +290,9 @@ sunrpc_debugfs_init(void)
        if (!rpc_xprt_dir)
                goto out_remove;
 
-       return 0;
+       return;
 out_remove:
        debugfs_remove_recursive(topdir);
        topdir = NULL;
-out:
-       return -ENOMEM;
+       rpc_clnt_dir = NULL;
 }
index e37fbed..ee5d3d2 100644 (file)
@@ -98,10 +98,7 @@ init_sunrpc(void)
        if (err)
                goto out4;
 
-       err = sunrpc_debugfs_init();
-       if (err)
-               goto out5;
-
+       sunrpc_debugfs_init();
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
        rpc_register_sysctl();
 #endif
@@ -109,8 +106,6 @@ init_sunrpc(void)
        init_socket_xprt();     /* clnt sock transport */
        return 0;
 
-out5:
-       unregister_rpc_pipefs();
 out4:
        unregister_pernet_subsys(&sunrpc_net_ops);
 out3:
index e3015ae..9949722 100644 (file)
@@ -1331,7 +1331,6 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
  */
 struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
 {
-       int err;
        struct rpc_xprt *xprt;
        struct xprt_class *t;
 
@@ -1372,11 +1371,7 @@ found:
                return ERR_PTR(-ENOMEM);
        }
 
-       err = rpc_xprt_debugfs_register(xprt);
-       if (err) {
-               xprt_destroy(xprt);
-               return ERR_PTR(err);
-       }
+       rpc_xprt_debugfs_register(xprt);
 
        dprintk("RPC:       created transport %p with %u slots\n", xprt,
                        xprt->max_reqs);
index 7e9acd9..91ffde8 100644 (file)
@@ -738,8 +738,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
        struct rpc_xprt *xprt = rep->rr_xprt;
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
        __be32 *iptr;
-       int credits, rdmalen, status;
+       int rdmalen, status;
        unsigned long cwnd;
+       u32 credits;
 
        /* Check status. If bad, signal disconnect and return rep to pool */
        if (rep->rr_len == ~0U) {
index d1b7039..0a16fb6 100644 (file)
@@ -285,7 +285,7 @@ rpcr_to_rdmar(struct rpc_rqst *rqst)
  */
 struct rpcrdma_buffer {
        spinlock_t      rb_lock;        /* protects indexes */
-       int             rb_max_requests;/* client max requests */
+       u32             rb_max_requests;/* client max requests */
        struct list_head rb_mws;        /* optional memory windows/fmrs/frmrs */
        struct list_head rb_all;
        int             rb_send_index;
index 935205e..be1c9fa 100644 (file)
@@ -152,11 +152,11 @@ out_netlink:
 static void __exit tipc_exit(void)
 {
        tipc_bearer_cleanup();
+       unregister_pernet_subsys(&tipc_net_ops);
        tipc_netlink_stop();
        tipc_netlink_compat_stop();
        tipc_socket_stop();
        tipc_unregister_sysctl();
-       unregister_pernet_subsys(&tipc_net_ops);
 
        pr_info("Deactivated\n");
 }
index a4cf364..14f09b3 100644 (file)
@@ -464,10 +464,11 @@ void tipc_link_reset(struct tipc_link *l_ptr)
        /* Clean up all queues, except inputq: */
        __skb_queue_purge(&l_ptr->outqueue);
        __skb_queue_purge(&l_ptr->deferred_queue);
-       skb_queue_splice_init(&l_ptr->wakeupq, &l_ptr->inputq);
-       if (!skb_queue_empty(&l_ptr->inputq))
+       if (!owner->inputq)
+               owner->inputq = &l_ptr->inputq;
+       skb_queue_splice_init(&l_ptr->wakeupq, owner->inputq);
+       if (!skb_queue_empty(owner->inputq))
                owner->action_flags |= TIPC_MSG_EVT;
-       owner->inputq = &l_ptr->inputq;
        l_ptr->next_out = NULL;
        l_ptr->unacked_window = 0;
        l_ptr->checkpoint = 1;
index f73e975..b4d4467 100644 (file)
@@ -2364,8 +2364,6 @@ int tipc_sk_rht_init(struct net *net)
                .hashfn = jhash,
                .max_shift = 20, /* 1M */
                .min_shift = 8,  /* 256 */
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        return rhashtable_init(&tn->sk_rht, &rht_params);
index 3af0ecf..2a0bbd2 100644 (file)
@@ -1199,6 +1199,7 @@ out_fail_wq:
        regulatory_exit();
 out_fail_reg:
        debugfs_remove(ieee80211_debugfs_dir);
+       nl80211_exit();
 out_fail_nl80211:
        unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 out_fail_notifier:
index d78fd8b..b6f84f6 100644 (file)
@@ -2654,10 +2654,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
                                  &flags);
@@ -2666,6 +2662,10 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
            !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
                return -EOPNOTSUPP;
 
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
        wdev = rdev_add_virtual_intf(rdev,
                                nla_data(info->attrs[NL80211_ATTR_IFNAME]),
                                type, err ? NULL : &flags, &params);
@@ -4400,6 +4400,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
+       /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
+        * as userspace might just pass through the capabilities from the IEs
+        * directly, rather than enforcing this restriction and returning an
+        * error in this case.
+        */
+       if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
+               params.ht_capa = NULL;
+               params.vht_capa = NULL;
+       }
+
        /* When you run into this, adjust the code below for the new flag */
        BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
 
@@ -12528,9 +12538,7 @@ static int cfg80211_net_detect_results(struct sk_buff *msg,
                        }
 
                        for (j = 0; j < match->n_channels; j++) {
-                               if (nla_put_u32(msg,
-                                               NL80211_ATTR_WIPHY_FREQ,
-                                               match->channels[j])) {
+                               if (nla_put_u32(msg, j, match->channels[j])) {
                                        nla_nest_cancel(msg, nl_freqs);
                                        nla_nest_cancel(msg, nl_match);
                                        goto out;
index b586d0d..48dfc7b 100644 (file)
@@ -228,7 +228,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
 
 /* We keep a static world regulatory domain in case of the absence of CRDA */
 static const struct ieee80211_regdomain world_regdom = {
-       .n_reg_rules = 6,
+       .n_reg_rules = 8,
        .alpha2 =  "00",
        .reg_rules = {
                /* IEEE 802.11b/g, channels 1..11 */
index cee479b..638af06 100644 (file)
@@ -2269,11 +2269,9 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
                 * have the xfrm_state's. We need to wait for KM to
                 * negotiate new SA's or bail out with error.*/
                if (net->xfrm.sysctl_larval_drop) {
-                       dst_release(dst);
-                       xfrm_pols_put(pols, drop_pols);
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-
-                       return ERR_PTR(-EREMOTE);
+                       err = -EREMOTE;
+                       goto error;
                }
 
                err = -EAGAIN;
@@ -2324,7 +2322,8 @@ nopol:
 error:
        dst_release(dst);
 dropdst:
-       dst_release(dst_orig);
+       if (!(flags & XFRM_LOOKUP_KEEP_DST_REF))
+               dst_release(dst_orig);
        xfrm_pols_put(pols, drop_pols);
        return ERR_PTR(err);
 }
@@ -2338,7 +2337,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
                                    struct sock *sk, int flags)
 {
        struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
-                                           flags | XFRM_LOOKUP_QUEUE);
+                                           flags | XFRM_LOOKUP_QUEUE |
+                                           XFRM_LOOKUP_KEEP_DST_REF);
 
        if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
                return make_blackhole(net, dst_orig->ops->family, dst_orig);
diff --git a/scripts/gdb/linux/__init__.py b/scripts/gdb/linux/__init__.py
new file mode 100644 (file)
index 0000000..4680fb1
--- /dev/null
@@ -0,0 +1 @@
+# nothing to do for the initialization of this package
index 1684bcc..5fde343 100644 (file)
@@ -152,7 +152,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
                goto out;
 
        /* No partial writes. */
-       length = EINVAL;
+       length = -EINVAL;
        if (*ppos != 0)
                goto out;
 
index 35324a8..eeb691d 100644 (file)
@@ -1170,6 +1170,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
 
        if (info->count < 1)
                return -EINVAL;
+       if (!*info->id.name)
+               return -EINVAL;
+       if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name))
+               return -EINVAL;
        access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
                (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
                                 SNDRV_CTL_ELEM_ACCESS_INACTIVE|
index b03a638..279e24f 100644 (file)
@@ -1552,6 +1552,8 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
                        if (! snd_pcm_playback_empty(substream)) {
                                snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);
                                snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING);
+                       } else {
+                               runtime->status->state = SNDRV_PCM_STATE_SETUP;
                        }
                        break;
                case SNDRV_PCM_STATE_RUNNING:
index f62780e..7821b07 100644 (file)
@@ -105,6 +105,8 @@ static void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum,
                int pitchbend = chan->midi_pitchbend;
                int segment;
 
+               if (pitchbend < -0x2000)
+                       pitchbend = -0x2000;
                if (pitchbend > 0x1FFF)
                        pitchbend = 0x1FFF;
 
index 0d58018..5cc356d 100644 (file)
@@ -33,7 +33,7 @@
  */
 #define MAX_MIDI_RX_BLOCKS     8
 
-#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 Ã‚µs */
+#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 microseconds */
 
 /* isochronous header parameters */
 #define ISO_DATA_LENGTH_SHIFT  16
@@ -78,7 +78,7 @@ static void pcm_period_tasklet(unsigned long data);
 int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
                      enum amdtp_stream_direction dir, enum cip_flags flags)
 {
-       s->unit = fw_unit_get(unit);
+       s->unit = unit;
        s->direction = dir;
        s->flags = flags;
        s->context = ERR_PTR(-1);
@@ -102,7 +102,6 @@ void amdtp_stream_destroy(struct amdtp_stream *s)
 {
        WARN_ON(amdtp_stream_running(s));
        mutex_destroy(&s->mutex);
-       fw_unit_put(s->unit);
 }
 EXPORT_SYMBOL(amdtp_stream_destroy);
 
index fc19c99..611b7da 100644 (file)
@@ -116,11 +116,22 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void
 bebob_card_free(struct snd_card *card)
 {
        struct snd_bebob *bebob = card->private_data;
 
+       snd_bebob_stream_destroy_duplex(bebob);
+       fw_unit_put(bebob->unit);
+
+       kfree(bebob->maudio_special_quirk);
+
        if (bebob->card_index >= 0) {
                mutex_lock(&devices_mutex);
                clear_bit(bebob->card_index, devices_used);
@@ -205,7 +216,7 @@ bebob_probe(struct fw_unit *unit,
        card->private_free = bebob_card_free;
 
        bebob->card = card;
-       bebob->unit = unit;
+       bebob->unit = fw_unit_get(unit);
        bebob->spec = spec;
        mutex_init(&bebob->mutex);
        spin_lock_init(&bebob->lock);
@@ -306,10 +317,11 @@ static void bebob_remove(struct fw_unit *unit)
        if (bebob == NULL)
                return;
 
-       kfree(bebob->maudio_special_quirk);
+       /* Awake bus-reset waiters. */
+       if (!completion_done(&bebob->bus_reset))
+               complete_all(&bebob->bus_reset);
 
-       snd_bebob_stream_destroy_duplex(bebob);
-       snd_card_disconnect(bebob->card);
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(bebob->card);
 }
 
index 0ebcabf..98e4fc8 100644 (file)
@@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob)
 static void
 destroy_both_connections(struct snd_bebob *bebob)
 {
-       break_both_connections(bebob);
-
        cmp_connection_destroy(&bebob->in_conn);
        cmp_connection_destroy(&bebob->out_conn);
 }
@@ -712,22 +710,16 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob)
        mutex_unlock(&bebob->mutex);
 }
 
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
 void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
 {
-       mutex_lock(&bebob->mutex);
-
-       amdtp_stream_pcm_abort(&bebob->rx_stream);
-       amdtp_stream_pcm_abort(&bebob->tx_stream);
-
-       amdtp_stream_stop(&bebob->rx_stream);
-       amdtp_stream_stop(&bebob->tx_stream);
-
        amdtp_stream_destroy(&bebob->rx_stream);
        amdtp_stream_destroy(&bebob->tx_stream);
 
        destroy_both_connections(bebob);
-
-       mutex_unlock(&bebob->mutex);
 }
 
 /*
index fa9cf76..07dbd01 100644 (file)
@@ -311,14 +311,21 @@ end:
        return err;
 }
 
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
 static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 {
-       amdtp_stream_destroy(stream);
+       struct fw_iso_resources *resources;
 
        if (stream == &dice->tx_stream)
-               fw_iso_resources_destroy(&dice->tx_resources);
+               resources = &dice->tx_resources;
        else
-               fw_iso_resources_destroy(&dice->rx_resources);
+               resources = &dice->rx_resources;
+
+       amdtp_stream_destroy(stream);
+       fw_iso_resources_destroy(resources);
 }
 
 int snd_dice_stream_init_duplex(struct snd_dice *dice)
@@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice)
                goto end;
 
        err = init_stream(dice, &dice->rx_stream);
+       if (err < 0)
+               destroy_stream(dice, &dice->tx_stream);
 end:
        return err;
 }
@@ -340,10 +349,7 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 {
        snd_dice_transaction_clear_enable(dice);
 
-       stop_stream(dice, &dice->tx_stream);
        destroy_stream(dice, &dice->tx_stream);
-
-       stop_stream(dice, &dice->rx_stream);
        destroy_stream(dice, &dice->rx_stream);
 
        dice->substreams_counter = 0;
index 90d8f40..70a111d 100644 (file)
@@ -226,11 +226,20 @@ static void dice_card_strings(struct snd_dice *dice)
        strcpy(card->mixername, "DICE");
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void dice_card_free(struct snd_card *card)
 {
        struct snd_dice *dice = card->private_data;
 
+       snd_dice_stream_destroy_duplex(dice);
        snd_dice_transaction_destroy(dice);
+       fw_unit_put(dice->unit);
+
        mutex_destroy(&dice->mutex);
 }
 
@@ -251,7 +260,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 
        dice = card->private_data;
        dice->card = card;
-       dice->unit = unit;
+       dice->unit = fw_unit_get(unit);
        card->private_free = dice_card_free;
 
        spin_lock_init(&dice->lock);
@@ -305,10 +314,7 @@ static void dice_remove(struct fw_unit *unit)
 {
        struct snd_dice *dice = dev_get_drvdata(&unit->device);
 
-       snd_card_disconnect(dice->card);
-
-       snd_dice_stream_destroy_duplex(dice);
-
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(dice->card);
 }
 
index 3e2ed8e..2682e7e 100644 (file)
@@ -173,11 +173,23 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void
 efw_card_free(struct snd_card *card)
 {
        struct snd_efw *efw = card->private_data;
 
+       snd_efw_stream_destroy_duplex(efw);
+       snd_efw_transaction_remove_instance(efw);
+       fw_unit_put(efw->unit);
+
+       kfree(efw->resp_buf);
+
        if (efw->card_index >= 0) {
                mutex_lock(&devices_mutex);
                clear_bit(efw->card_index, devices_used);
@@ -185,7 +197,6 @@ efw_card_free(struct snd_card *card)
        }
 
        mutex_destroy(&efw->mutex);
-       kfree(efw->resp_buf);
 }
 
 static int
@@ -218,7 +229,7 @@ efw_probe(struct fw_unit *unit,
        card->private_free = efw_card_free;
 
        efw->card = card;
-       efw->unit = unit;
+       efw->unit = fw_unit_get(unit);
        mutex_init(&efw->mutex);
        spin_lock_init(&efw->lock);
        init_waitqueue_head(&efw->hwdep_wait);
@@ -289,10 +300,7 @@ static void efw_remove(struct fw_unit *unit)
 {
        struct snd_efw *efw = dev_get_drvdata(&unit->device);
 
-       snd_efw_stream_destroy_duplex(efw);
-       snd_efw_transaction_remove_instance(efw);
-
-       snd_card_disconnect(efw->card);
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(efw->card);
 }
 
index 4f440e1..c55db1b 100644 (file)
@@ -100,17 +100,22 @@ end:
        return err;
 }
 
+/*
+ * This function should be called before starting the stream or after stopping
+ * the streams.
+ */
 static void
 destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
 {
-       stop_stream(efw, stream);
-
-       amdtp_stream_destroy(stream);
+       struct cmp_connection *conn;
 
        if (stream == &efw->tx_stream)
-               cmp_connection_destroy(&efw->out_conn);
+               conn = &efw->out_conn;
        else
-               cmp_connection_destroy(&efw->in_conn);
+               conn = &efw->in_conn;
+
+       amdtp_stream_destroy(stream);
+       cmp_connection_destroy(&efw->out_conn);
 }
 
 static int
@@ -319,12 +324,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw)
 
 void snd_efw_stream_destroy_duplex(struct snd_efw *efw)
 {
-       mutex_lock(&efw->mutex);
-
        destroy_stream(efw, &efw->rx_stream);
        destroy_stream(efw, &efw->tx_stream);
-
-       mutex_unlock(&efw->mutex);
 }
 
 void snd_efw_stream_lock_changed(struct snd_efw *efw)
index 5f17b77..f0e4d50 100644 (file)
@@ -26,7 +26,7 @@
 int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
 {
        r->channels_mask = ~0uLL;
-       r->unit = fw_unit_get(unit);
+       r->unit = unit;
        mutex_init(&r->mutex);
        r->allocated = false;
 
@@ -42,7 +42,6 @@ void fw_iso_resources_destroy(struct fw_iso_resources *r)
 {
        WARN_ON(r->allocated);
        mutex_destroy(&r->mutex);
-       fw_unit_put(r->unit);
 }
 EXPORT_SYMBOL(fw_iso_resources_destroy);
 
index bda845a..e6757cd 100644 (file)
@@ -171,9 +171,10 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
        }
 
        /* Wait first packet */
-       err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT);
-       if (err < 0)
+       if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
                stop_stream(oxfw, stream);
+               err = -ETIMEDOUT;
+       }
 end:
        return err;
 }
@@ -337,6 +338,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
        stop_stream(oxfw, stream);
 }
 
+/*
+ * This function should be called before starting the stream or after stopping
+ * the streams.
+ */
 void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
                                     struct amdtp_stream *stream)
 {
@@ -347,8 +352,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
        else
                conn = &oxfw->in_conn;
 
-       stop_stream(oxfw, stream);
-
        amdtp_stream_destroy(stream);
        cmp_connection_destroy(conn);
 }
index 60e5cad..8c6ce01 100644 (file)
@@ -104,11 +104,23 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void oxfw_card_free(struct snd_card *card)
 {
        struct snd_oxfw *oxfw = card->private_data;
        unsigned int i;
 
+       snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
+       if (oxfw->has_output)
+               snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+
+       fw_unit_put(oxfw->unit);
+
        for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
                kfree(oxfw->tx_stream_formats[i]);
                kfree(oxfw->rx_stream_formats[i]);
@@ -136,7 +148,7 @@ static int oxfw_probe(struct fw_unit *unit,
        oxfw = card->private_data;
        oxfw->card = card;
        mutex_init(&oxfw->mutex);
-       oxfw->unit = unit;
+       oxfw->unit = fw_unit_get(unit);
        oxfw->device_info = (const struct device_info *)id->driver_data;
        spin_lock_init(&oxfw->lock);
        init_waitqueue_head(&oxfw->hwdep_wait);
@@ -212,12 +224,7 @@ static void oxfw_remove(struct fw_unit *unit)
 {
        struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
 
-       snd_card_disconnect(oxfw->card);
-
-       snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
-       if (oxfw->has_output)
-               snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
-
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(oxfw->card);
 }
 
index 17e49a0..b408540 100644 (file)
@@ -306,11 +306,12 @@ int snd_msndmix_new(struct snd_card *card)
        spin_lock_init(&chip->mixer_lock);
        strcpy(card->mixername, "MSND Pinnacle Mixer");
 
-       for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
+       for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) {
                err = snd_ctl_add(card,
                                  snd_ctl_new1(snd_msnd_controls + idx, chip));
                if (err < 0)
                        return err;
+       }
 
        return 0;
 }
index dfcb5e9..17c2637 100644 (file)
@@ -961,7 +961,6 @@ static int azx_alloc_cmd_io(struct azx *chip)
                dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
        return err;
 }
-EXPORT_SYMBOL_GPL(azx_alloc_cmd_io);
 
 static void azx_init_cmd_io(struct azx *chip)
 {
@@ -1026,7 +1025,6 @@ static void azx_init_cmd_io(struct azx *chip)
        azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
        spin_unlock_irq(&chip->reg_lock);
 }
-EXPORT_SYMBOL_GPL(azx_init_cmd_io);
 
 static void azx_free_cmd_io(struct azx *chip)
 {
@@ -1036,7 +1034,6 @@ static void azx_free_cmd_io(struct azx *chip)
        azx_writeb(chip, CORBCTL, 0);
        spin_unlock_irq(&chip->reg_lock);
 }
-EXPORT_SYMBOL_GPL(azx_free_cmd_io);
 
 static unsigned int azx_command_addr(u32 cmd)
 {
@@ -1167,7 +1164,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                }
        }
 
-       if (!bus->no_response_fallback)
+       if (bus->no_response_fallback)
                return -1;
 
        if (!chip->polling_mode && chip->poll_count < 2) {
@@ -1316,7 +1313,6 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
        else
                return azx_corb_send_cmd(bus, val);
 }
-EXPORT_SYMBOL_GPL(azx_send_cmd);
 
 /* get a response */
 static unsigned int azx_get_response(struct hda_bus *bus,
@@ -1330,7 +1326,6 @@ static unsigned int azx_get_response(struct hda_bus *bus,
        else
                return azx_rirb_get_response(bus, addr);
 }
-EXPORT_SYMBOL_GPL(azx_get_response);
 
 #ifdef CONFIG_SND_HDA_DSP_LOADER
 /*
index b680b4e..8ec5289 100644 (file)
@@ -687,12 +687,45 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
        return val;
 }
 
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+       unsigned int wcaps = get_wcaps(codec, nid);
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+       if (snd_hda_get_num_conns(codec, nid) != 1)
+               return false;
+       if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
+}
+
 /* initialize the amp value (only at the first time) */
 static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
 {
        unsigned int caps = query_amp_caps(codec, nid, dir);
        int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
-       snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+
+       if (is_stereo_amps(codec, nid, dir))
+               snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+       else
+               snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
+}
+
+/* update the amp, doing in stereo or mono depending on NID */
+static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
+                     unsigned int mask, unsigned int val)
+{
+       if (is_stereo_amps(codec, nid, dir))
+               return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
+                                               mask, val);
+       else
+               return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+                                               mask, val);
 }
 
 /* calculate amp value mask we can modify;
@@ -732,7 +765,7 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
                return;
 
        val &= mask;
-       snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val);
+       update_amp(codec, nid, dir, idx, mask, val);
 }
 
 static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
@@ -4424,13 +4457,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
        has_amp = nid_has_mute(codec, mix, HDA_INPUT);
        for (i = 0; i < nums; i++) {
                if (has_amp)
-                       snd_hda_codec_amp_stereo(codec, mix,
-                                                HDA_INPUT, i,
-                                                0xff, HDA_AMP_MUTE);
+                       update_amp(codec, mix, HDA_INPUT, i,
+                                  0xff, HDA_AMP_MUTE);
                else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
-                       snd_hda_codec_amp_stereo(codec, conn[i],
-                                                HDA_OUTPUT, 0,
-                                                0xff, HDA_AMP_MUTE);
+                       update_amp(codec, conn[i], HDA_OUTPUT, 0,
+                                  0xff, HDA_AMP_MUTE);
        }
 }
 
index 36d2f20..a8a1e14 100644 (file)
@@ -1966,7 +1966,7 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Panther Point */
        { PCI_DEVICE(0x8086, 0x1e20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Lynx Point */
        { PCI_DEVICE(0x8086, 0x8c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -1989,7 +1989,7 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
        /* Sunrise Point */
        { PCI_DEVICE(0x8086, 0xa170),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
index ce5a6da..05e19f7 100644 (file)
@@ -134,13 +134,38 @@ static void print_amp_caps(struct snd_info_buffer *buffer,
                    (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
 }
 
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int wcaps, int indices)
+{
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       /* check for a stereo-to-mono mix; it must be:
+        * only a single connection, only for input, and only a mixer widget
+        */
+       if (indices != 1 || dir != HDA_INPUT ||
+           get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+
+       if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       /* the connection source is a stereo? */
+       wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP);
+       return !!(wcaps & AC_WCAP_STEREO);
+}
+
 static void print_amp_vals(struct snd_info_buffer *buffer,
                           struct hda_codec *codec, hda_nid_t nid,
-                          int dir, int stereo, int indices)
+                          int dir, unsigned int wcaps, int indices)
 {
        unsigned int val;
+       bool stereo;
        int i;
 
+       stereo = is_stereo_amps(codec, nid, dir, wcaps, indices);
+
        dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
        for (i = 0; i < indices; i++) {
                snd_iprintf(buffer, " [");
@@ -757,12 +782,10 @@ static void print_codec_info(struct snd_info_entry *entry,
                            (codec->single_adc_amp &&
                             wid_type == AC_WID_AUD_IN))
                                print_amp_vals(buffer, codec, nid, HDA_INPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              1);
+                                              wid_caps, 1);
                        else
                                print_amp_vals(buffer, codec, nid, HDA_INPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              conn_len);
+                                              wid_caps, conn_len);
                }
                if (wid_caps & AC_WCAP_OUT_AMP) {
                        snd_iprintf(buffer, "  Amp-Out caps: ");
@@ -771,11 +794,10 @@ static void print_codec_info(struct snd_info_entry *entry,
                        if (wid_type == AC_WID_PIN &&
                            codec->pin_amp_workaround)
                                print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              conn_len);
+                                              wid_caps, conn_len);
                        else
                                print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                              wid_caps & AC_WCAP_STEREO, 1);
+                                              wid_caps, 1);
                }
 
                switch (wid_type) {
index 1589c9b..dd2b3d9 100644 (file)
@@ -393,6 +393,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
        SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
        SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
+       SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81),
        SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
        SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
        {} /* terminator */
@@ -584,6 +585,7 @@ static int patch_cs420x(struct hda_codec *codec)
                return -ENOMEM;
 
        spec->gen.automute_hook = cs_automute;
+       codec->single_adc_amp = 1;
 
        snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
                           cs420x_fixups);
index fd3ed18..da67ea8 100644 (file)
@@ -223,6 +223,7 @@ enum {
        CXT_PINCFG_LENOVO_TP410,
        CXT_PINCFG_LEMOTE_A1004,
        CXT_PINCFG_LEMOTE_A1205,
+       CXT_PINCFG_COMPAQ_CQ60,
        CXT_FIXUP_STEREO_DMIC,
        CXT_FIXUP_INC_MIC_BOOST,
        CXT_FIXUP_HEADPHONE_MIC_PIN,
@@ -660,6 +661,15 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = cxt_pincfg_lemote,
        },
+       [CXT_PINCFG_COMPAQ_CQ60] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* 0x17 was falsely set up as a mic, it should 0x1d */
+                       { 0x17, 0x400001f0 },
+                       { 0x1d, 0x97a70120 },
+                       { }
+               }
+       },
        [CXT_FIXUP_STEREO_DMIC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt_fixup_stereo_dmic,
@@ -769,6 +779,7 @@ static const struct hda_model_fixup cxt5047_fixup_models[] = {
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
+       SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
        {}
 };
index b2b24a8..7438213 100644 (file)
@@ -396,7 +396,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
 {
        /* We currently only handle front, HP */
        static hda_nid_t pins[] = {
-               0x0f, 0x10, 0x14, 0x15, 0
+               0x0f, 0x10, 0x14, 0x15, 0x17, 0
        };
        hda_nid_t *p;
        for (p = pins; *p; p++)
@@ -5036,6 +5036,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
@@ -5209,6 +5210,13 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x17, 0x40000000},
                {0x1d, 0x40700001},
                {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
+               {0x12, 0x90a60170},
+               {0x14, 0x90170140},
+               {0x17, 0x40000000},
+               {0x1d, 0x40700001},
+               {0x21, 0x02211050}),
        SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
                {0x12, 0x90a60130},
                {0x13, 0x40000000},
index 6d36c5b..87eff31 100644 (file)
@@ -79,6 +79,7 @@ enum {
        STAC_ALIENWARE_M17X,
        STAC_92HD89XX_HP_FRONT_JACK,
        STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
+       STAC_92HD73XX_ASUS_MOBO,
        STAC_92HD73XX_MODELS
 };
 
@@ -1911,7 +1912,18 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
        [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs,
-       }
+       },
+       [STAC_92HD73XX_ASUS_MOBO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* enable 5.1 and SPDIF out */
+                       { 0x0c, 0x01014411 },
+                       { 0x0d, 0x01014410 },
+                       { 0x0e, 0x01014412 },
+                       { 0x22, 0x014b1180 },
+                       { }
+               }
+       },
 };
 
 static const struct hda_model_fixup stac92hd73xx_models[] = {
@@ -1923,6 +1935,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
        { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
        { .id = STAC_DELL_EQ, .name = "dell-eq" },
        { .id = STAC_ALIENWARE_M17X, .name = "alienware" },
+       { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
        {}
 };
 
@@ -1975,6 +1988,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
                                "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
                                "unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10",
+                     STAC_92HD73XX_ASUS_MOBO),
        {} /* terminator */
 };
 
index 1579e99..e7d0880 100644 (file)
@@ -25,7 +25,8 @@ config SND_ATMEL_SOC_SSC
 
 config SND_AT91_SOC_SAM9G20_WM8731
        tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
-       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
+       depends on ARCH_AT91 || COMPILE_TEST
+       depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI
        select SND_ATMEL_SOC_PDC
        select SND_ATMEL_SOC_SSC
        select SND_SOC_WM8731
@@ -35,7 +36,8 @@ config SND_AT91_SOC_SAM9G20_WM8731
 
 config SND_ATMEL_SOC_WM8904
        tristate "Atmel ASoC driver for boards using WM8904 codec"
-       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && I2C
+       depends on ARCH_AT91 || COMPILE_TEST
+       depends on ATMEL_SSC && SND_ATMEL_SOC && I2C
        select SND_ATMEL_SOC_SSC
        select SND_ATMEL_SOC_DMA
        select SND_SOC_WM8904
@@ -45,7 +47,8 @@ config SND_ATMEL_SOC_WM8904
 
 config SND_AT91_SOC_SAM9X5_WM8731
        tristate "SoC Audio support for WM8731-based at91sam9x5 board"
-       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
+       depends on ARCH_AT91 || COMPILE_TEST
+       depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI
        select SND_ATMEL_SOC_SSC
        select SND_ATMEL_SOC_DMA
        select SND_SOC_WM8731
index 466a821..b327e5c 100644 (file)
@@ -1,10 +1,8 @@
 # AT91 Platform Support
-snd-soc-atmel-pcm-objs := atmel-pcm.o
 snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
 snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
 snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
 
-obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o
 obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
 obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
 obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
index b8e7bad..b6625c8 100644 (file)
@@ -54,7 +54,7 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
        .period_bytes_max       = 2 * 0xffff,   /* if 2 bytes format */
        .periods_min            = 8,
        .periods_max            = 1024,         /* no limit */
-       .buffer_bytes_max       = ATMEL_SSC_DMABUF_SIZE,
+       .buffer_bytes_max       = 512 * 1024,
 };
 
 /**
@@ -119,7 +119,7 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
 static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = {
        .prepare_slave_config = atmel_pcm_configure_dma,
        .pcm_hardware = &atmel_pcm_dma_hardware,
-       .prealloc_buffer_size = ATMEL_SSC_DMABUF_SIZE,
+       .prealloc_buffer_size = 64 * 1024,
 };
 
 int atmel_pcm_dma_platform_register(struct device *dev)
index a366b35..da861b4 100644 (file)
 #include "atmel-pcm.h"
 
 
+static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+       int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       size_t size = ATMEL_SSC_DMABUF_SIZE;
+
+       buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+       buf->area = dma_alloc_coherent(pcm->card->dev, size,
+                       &buf->addr, GFP_KERNEL);
+       pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
+                       (void *)buf->area, (void *)(long)buf->addr, size);
+
+       if (!buf->area)
+               return -ENOMEM;
+
+       buf->bytes = size;
+       return 0;
+}
+
+static int atmel_pcm_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
+{
+       return remap_pfn_range(vma, vma->vm_start,
+                      substream->dma_buffer.addr >> PAGE_SHIFT,
+                      vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
+       int ret;
+
+       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+               pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
+               ret = atmel_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n");
+               ret = atmel_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+ out:
+       return ret;
+}
+
+static void atmel_pcm_free(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (!substream)
+                       continue;
+
+               buf = &substream->dma_buffer;
+               if (!buf->area)
+                       continue;
+               dma_free_coherent(pcm->card->dev, buf->bytes,
+                                 buf->area, buf->addr);
+               buf->area = NULL;
+       }
+}
+
 /*--------------------------------------------------------------------------*\
  * Hardware definition
 \*--------------------------------------------------------------------------*/
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
deleted file mode 100644 (file)
index 8ae3fa5..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * atmel-pcm.c  --  ALSA PCM interface for the Atmel atmel SoC.
- *
- *  Copyright (C) 2005 SAN People
- *  Copyright (C) 2008 Atmel
- *
- * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
- *
- * Based on at91-pcm. by:
- * Frank Mandarino <fmandarino@endrelia.com>
- * Copyright 2006 Endrelia Technologies Inc.
- *
- * Based on pxa2xx-pcm.c by:
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 30, 2004
- * Copyright:  (C) 2004 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include "atmel-pcm.h"
-
-static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
-       int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = ATMEL_SSC_DMABUF_SIZE;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_coherent(pcm->card->dev, size,
-                       &buf->addr, GFP_KERNEL);
-       pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
-                       (void *)buf->area, (void *)(long)buf->addr, size);
-
-       if (!buf->area)
-               return -ENOMEM;
-
-       buf->bytes = size;
-       return 0;
-}
-
-int atmel_pcm_mmap(struct snd_pcm_substream *substream,
-       struct vm_area_struct *vma)
-{
-       return remap_pfn_range(vma, vma->vm_start,
-                      substream->dma_buffer.addr >> PAGE_SHIFT,
-                      vma->vm_end - vma->vm_start, vma->vm_page_prot);
-}
-EXPORT_SYMBOL_GPL(atmel_pcm_mmap);
-
-int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret;
-
-       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
-               ret = atmel_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n");
-               ret = atmel_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
- out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(atmel_pcm_new);
-
-void atmel_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-               dma_free_coherent(pcm->card->dev, buf->bytes,
-                                 buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-EXPORT_SYMBOL_GPL(atmel_pcm_free);
-
index 12ae814..6eaf081 100644 (file)
@@ -83,11 +83,6 @@ struct atmel_pcm_dma_params {
 #define ssc_readx(base, reg)            (__raw_readl((base) + (reg)))
 #define ssc_writex(base, reg, value)    __raw_writel((value), (base) + (reg))
 
-int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd);
-void atmel_pcm_free(struct snd_pcm *pcm);
-int atmel_pcm_mmap(struct snd_pcm_substream *substream,
-               struct vm_area_struct *vma);
-
 #if defined(CONFIG_SND_ATMEL_SOC_PDC) || \
        defined(CONFIG_SND_ATMEL_SOC_PDC_MODULE)
 int atmel_pcm_pdc_platform_register(struct device *dev);
index fb0b7e8..841d059 100644 (file)
@@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+/*
+ * When the bit clock is input, limit the maximum rate according to the
+ * Serial Clock Ratio Considerations section from the SSC documentation:
+ *
+ *   The Transmitter and the Receiver can be programmed to operate
+ *   with the clock signals provided on either the TK or RK pins.
+ *   This allows the SSC to support many slave-mode data transfers.
+ *   In this case, the maximum clock speed allowed on the RK pin is:
+ *   - Peripheral clock divided by 2 if Receiver Frame Synchro is input
+ *   - Peripheral clock divided by 3 if Receiver Frame Synchro is output
+ *   In addition, the maximum clock speed allowed on the TK pin is:
+ *   - Peripheral clock divided by 6 if Transmit Frame Synchro is input
+ *   - Peripheral clock divided by 2 if Transmit Frame Synchro is output
+ *
+ * When the bit clock is output, limit the rate according to the
+ * SSC divider restrictions.
+ */
+static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
+                                 struct snd_pcm_hw_rule *rule)
+{
+       struct atmel_ssc_info *ssc_p = rule->private;
+       struct ssc_device *ssc = ssc_p->ssc;
+       struct snd_interval *i = hw_param_interval(params, rule->var);
+       struct snd_interval t;
+       struct snd_ratnum r = {
+               .den_min = 1,
+               .den_max = 4095,
+               .den_step = 1,
+       };
+       unsigned int num = 0, den = 0;
+       int frame_size;
+       int mck_div = 2;
+       int ret;
+
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0)
+               return frame_size;
+
+       switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFS:
+               if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE)
+                   && ssc->clk_from_rk_pin)
+                       /* Receiver Frame Synchro (i.e. capture)
+                        * is output (format is _CFS) and the RK pin
+                        * is used for input (format is _CBM_).
+                        */
+                       mck_div = 3;
+               break;
+
+       case SND_SOC_DAIFMT_CBM_CFM:
+               if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK)
+                   && !ssc->clk_from_rk_pin)
+                       /* Transmit Frame Synchro (i.e. playback)
+                        * is input (format is _CFM) and the TK pin
+                        * is used for input (format _CBM_ but not
+                        * using the RK pin).
+                        */
+                       mck_div = 6;
+               break;
+       }
+
+       switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               r.num = ssc_p->mck_rate / mck_div / frame_size;
+
+               ret = snd_interval_ratnum(i, 1, &r, &num, &den);
+               if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
+                       params->rate_num = num;
+                       params->rate_den = den;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBM_CFM:
+               t.min = 8000;
+               t.max = ssc_p->mck_rate / mck_div / frame_size;
+               t.openmin = t.openmax = 0;
+               t.integer = 0;
+               ret = snd_interval_refine(i, &t);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
 
 /*-------------------------------------------------------------------------*\
  * DAI functions
@@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
        struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
        struct atmel_pcm_dma_params *dma_params;
        int dir, dir_mask;
+       int ret;
 
        pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
                ssc_readl(ssc_p->ssc->regs, SR));
@@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
        /* Enable PMC peripheral clock for this SSC */
        pr_debug("atmel_ssc_dai: Starting clock\n");
        clk_enable(ssc_p->ssc->clk);
+       ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);
 
        /* Reset the SSC to keep it at a clean status */
        ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
@@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
                dir_mask = SSC_DIR_MASK_CAPTURE;
        }
 
+       ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_RATE,
+                                 atmel_ssc_hw_rule_rate,
+                                 ssc_p,
+                                 SNDRV_PCM_HW_PARAM_FRAME_BITS,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+       if (ret < 0) {
+               dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret);
+               return ret;
+       }
+
        dma_params = &ssc_dma_params[dai->id][dir];
        dma_params->ssc = ssc_p->ssc;
        dma_params->substream = substream;
@@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
 #  define atmel_ssc_resume     NULL
 #endif /* CONFIG_PM */
 
-#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
-
 #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
                          SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
@@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
                .playback = {
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = ATMEL_SSC_RATES,
+                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                       .rate_min = 8000,
+                       .rate_max = 384000,
                        .formats = ATMEL_SSC_FORMATS,},
                .capture = {
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = ATMEL_SSC_RATES,
+                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                       .rate_min = 8000,
+                       .rate_max = 384000,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
 };
index b1f08d5..80b1538 100644 (file)
@@ -115,6 +115,7 @@ struct atmel_ssc_info {
        unsigned short rcmr_period;
        struct atmel_pcm_dma_params *dma_params[2];
        struct atmel_ssc_state ssc_state;
+       unsigned long mck_rate;
 };
 
 int atmel_ssc_set_audio(int ssc_id);
index f5ad214..8de8361 100644 (file)
@@ -46,8 +46,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include <asm/mach-types.h>
-
 #include "../codecs/wm8731.h"
 #include "atmel-pcm.h"
 #include "atmel_ssc_dai.h"
@@ -171,9 +169,7 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
        int ret;
 
        if (!np) {
-               if (!(machine_is_at91sam9g20ek() ||
-                       machine_is_at91sam9g20ek_2mmc()))
-                       return -ENODEV;
+               return -ENODEV;
        }
 
        ret = atmel_ssc_set_audio(0);
@@ -210,39 +206,37 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
        card->dev = &pdev->dev;
 
        /* Parse device node info */
-       if (np) {
-               ret = snd_soc_of_parse_card_name(card, "atmel,model");
-               if (ret)
-                       goto err;
-
-               ret = snd_soc_of_parse_audio_routing(card,
-                       "atmel,audio-routing");
-               if (ret)
-                       goto err;
-
-               /* Parse codec info */
-               at91sam9g20ek_dai.codec_name = NULL;
-               codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
-               if (!codec_np) {
-                       dev_err(&pdev->dev, "codec info missing\n");
-                       return -EINVAL;
-               }
-               at91sam9g20ek_dai.codec_of_node = codec_np;
-
-               /* Parse dai and platform info */
-               at91sam9g20ek_dai.cpu_dai_name = NULL;
-               at91sam9g20ek_dai.platform_name = NULL;
-               cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
-               if (!cpu_np) {
-                       dev_err(&pdev->dev, "dai and pcm info missing\n");
-                       return -EINVAL;
-               }
-               at91sam9g20ek_dai.cpu_of_node = cpu_np;
-               at91sam9g20ek_dai.platform_of_node = cpu_np;
-
-               of_node_put(codec_np);
-               of_node_put(cpu_np);
+       ret = snd_soc_of_parse_card_name(card, "atmel,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card,
+               "atmel,audio-routing");
+       if (ret)
+               goto err;
+
+       /* Parse codec info */
+       at91sam9g20ek_dai.codec_name = NULL;
+       codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+       if (!codec_np) {
+               dev_err(&pdev->dev, "codec info missing\n");
+               return -EINVAL;
+       }
+       at91sam9g20ek_dai.codec_of_node = codec_np;
+
+       /* Parse dai and platform info */
+       at91sam9g20ek_dai.cpu_dai_name = NULL;
+       at91sam9g20ek_dai.platform_name = NULL;
+       cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "dai and pcm info missing\n");
+               return -EINVAL;
        }
+       at91sam9g20ek_dai.cpu_of_node = cpu_np;
+       at91sam9g20ek_dai.platform_of_node = cpu_np;
+
+       of_node_put(codec_np);
+       of_node_put(cpu_np);
 
        ret = snd_soc_register_card(card);
        if (ret) {
index 7b7fbcd..c7cd60f 100644 (file)
@@ -16,7 +16,7 @@ config SND_EP93XX_SOC_AC97
 
 config SND_EP93XX_SOC_SNAPPERCL15
         tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
-        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
+        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C
         select SND_EP93XX_SOC_I2S
         select SND_SOC_TLV320AIC23_I2C
         help
index 064e6c1..0bddd92 100644 (file)
@@ -69,7 +69,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MAX98088 if I2C
        select SND_SOC_MAX98090 if I2C
        select SND_SOC_MAX98095 if I2C
-       select SND_SOC_MAX98357A
+       select SND_SOC_MAX98357A if GPIOLIB
        select SND_SOC_MAX9850 if I2C
        select SND_SOC_MAX9768 if I2C
        select SND_SOC_MAX9877 if I2C
@@ -141,7 +141,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8770 if SPI_MASTER
        select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8782
-       select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8804_I2C if I2C
+       select SND_SOC_WM8804_SPI if SPI_MASTER
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
@@ -744,8 +745,19 @@ config SND_SOC_WM8782
        tristate
 
 config SND_SOC_WM8804
-       tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver"
-       depends on SND_SOC_I2C_AND_SPI
+       tristate
+
+config SND_SOC_WM8804_I2C
+       tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C"
+       depends on I2C
+       select SND_SOC_WM8804
+       select REGMAP_I2C
+
+config SND_SOC_WM8804_SPI
+       tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI"
+       depends on SPI_MASTER
+       select SND_SOC_WM8804
+       select REGMAP_SPI
 
 config SND_SOC_WM8900
        tristate
index 69b8666..7acb6c1 100644 (file)
@@ -145,6 +145,8 @@ snd-soc-wm8770-objs := wm8770.o
 snd-soc-wm8776-objs := wm8776.o
 snd-soc-wm8782-objs := wm8782.o
 snd-soc-wm8804-objs := wm8804.o
+snd-soc-wm8804-i2c-objs := wm8804-i2c.o
+snd-soc-wm8804-spi-objs := wm8804-spi.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
@@ -323,6 +325,8 @@ obj-$(CONFIG_SND_SOC_WM8770)        += snd-soc-wm8770.o
 obj-$(CONFIG_SND_SOC_WM8776)   += snd-soc-wm8776.o
 obj-$(CONFIG_SND_SOC_WM8782)   += snd-soc-wm8782.o
 obj-$(CONFIG_SND_SOC_WM8804)   += snd-soc-wm8804.o
+obj-$(CONFIG_SND_SOC_WM8804_I2C) += snd-soc-wm8804-i2c.o
+obj-$(CONFIG_SND_SOC_WM8804_SPI) += snd-soc-wm8804-spi.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
index 7895689..88ca9cb 100644 (file)
@@ -2003,7 +2003,6 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(ab8500_audio_setup_mics);
 
 static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec,
                                enum ear_cm_voltage ear_cmv)
@@ -2036,7 +2035,6 @@ static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(ab8500_audio_set_ear_cmv);
 
 static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai,
                                unsigned int delay)
index 70ab357..7ad8e15 100644 (file)
@@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap,
                adau1977->dvdd_reg = NULL;
        }
 
-       adau1977->reset_gpio = devm_gpiod_get(dev, "reset");
-       if (IS_ERR(adau1977->reset_gpio)) {
-               ret = PTR_ERR(adau1977->reset_gpio);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return PTR_ERR(adau1977->reset_gpio);
-               adau1977->reset_gpio = NULL;
-       }
+       adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+                                                      GPIOD_OUT_LOW);
+       if (IS_ERR(adau1977->reset_gpio))
+               return PTR_ERR(adau1977->reset_gpio);
 
        dev_set_drvdata(dev, adau1977);
 
-       if (adau1977->reset_gpio) {
-               ret = gpiod_direction_output(adau1977->reset_gpio, 0);
-               if (ret)
-                       return ret;
+       if (adau1977->reset_gpio)
                ndelay(100);
-       }
 
        ret = adau1977_power_enable(adau1977);
        if (ret)
index b67480f..4373ada 100644 (file)
@@ -317,7 +317,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-       unsigned int deemph = ucontrol->value.enumerated.item[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
@@ -333,7 +333,7 @@ static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = adav80x->deemph;
+       ucontrol->value.integer.value[0] = adav80x->deemph;
        return 0;
 };
 
index 16ce9f9..298dedc 100644 (file)
@@ -84,7 +84,7 @@ static int ak4554_soc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id ak4554_of_match[] = {
+static const struct of_device_id ak4554_of_match[] = {
        { .compatible = "asahi-kasei,ak4554" },
        {},
 };
index 70861c7..81b54a2 100644 (file)
@@ -76,7 +76,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
@@ -92,7 +92,7 @@ static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = ak4641->deemph;
+       ucontrol->value.integer.value[0] = ak4641->deemph;
        return 0;
 };
 
index dde8b49..13585e8 100644 (file)
@@ -97,6 +97,9 @@
 #define PMMP           (1 << 2) /* MPWR pin Power Management */
 #define MGAIN0         (1 << 0) /* MIC amp gain*/
 
+/* SG_SL2 */
+#define LOPS           (1 << 6) /* Stero Line-out Power Save Mode */
+
 /* TIMER */
 #define ZTM(param)     ((param & 0x3) << 4) /* ALC Zero Crossing TimeOut */
 #define WTM(param)     (((param & 0x4) << 4) | ((param & 0x3) << 2))
@@ -168,6 +171,29 @@ static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = {
        SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0),
 };
 
+/* event handlers */
+static int ak4642_lout_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMD:
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Power save mode ON */
+               snd_soc_update_bits(codec, SG_SL2, LOPS, LOPS);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               /* Power save mode OFF */
+               mdelay(300);
+               snd_soc_update_bits(codec, SG_SL2, LOPS, 0);
+               break;
+       }
+
+       return 0;
+}
+
 static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
 
        /* Outputs */
@@ -182,12 +208,15 @@ static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
 
        SND_SOC_DAPM_PGA("DACH", MD_CTL4, 0, 0, NULL, 0),
 
-       SND_SOC_DAPM_MIXER("LINEOUT Mixer", PW_MGMT1, 3, 0,
+       SND_SOC_DAPM_MIXER_E("LINEOUT Mixer", PW_MGMT1, 3, 0,
                           &ak4642_lout_mixer_controls[0],
-                          ARRAY_SIZE(ak4642_lout_mixer_controls)),
+                          ARRAY_SIZE(ak4642_lout_mixer_controls),
+                          ak4642_lout_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
        /* DAC */
-       SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0),
+       SND_SOC_DAPM_DAC("DAC", NULL, PW_MGMT1, 2, 0),
 };
 
 static const struct snd_soc_dapm_route ak4642_intercon[] = {
@@ -205,6 +234,8 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = {
        {"DACH", NULL, "DAC"},
 
        {"LINEOUT Mixer", "DACL", "DAC"},
+
+       { "DAC", NULL, "Playback" },
 };
 
 /*
@@ -468,13 +499,13 @@ static struct snd_soc_dai_driver ak4642_dai = {
        .name = "ak4642-hifi",
        .playback = {
                .stream_name = "Playback",
-               .channels_min = 1,
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_48000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE },
        .capture = {
                .stream_name = "Capture",
-               .channels_min = 1,
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_48000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE },
index 632e89f..2a58b1d 100644 (file)
@@ -343,25 +343,25 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route ak4671_intercon[] = {
-       {"DAC Left", "NULL", "PMPLL"},
-       {"DAC Right", "NULL", "PMPLL"},
-       {"ADC Left", "NULL", "PMPLL"},
-       {"ADC Right", "NULL", "PMPLL"},
+       {"DAC Left", NULL, "PMPLL"},
+       {"DAC Right", NULL, "PMPLL"},
+       {"ADC Left", NULL, "PMPLL"},
+       {"ADC Right", NULL, "PMPLL"},
 
        /* Outputs */
-       {"LOUT1", "NULL", "LOUT1 Mixer"},
-       {"ROUT1", "NULL", "ROUT1 Mixer"},
-       {"LOUT2", "NULL", "LOUT2 Mix Amp"},
-       {"ROUT2", "NULL", "ROUT2 Mix Amp"},
-       {"LOUT3", "NULL", "LOUT3 Mixer"},
-       {"ROUT3", "NULL", "ROUT3 Mixer"},
+       {"LOUT1", NULL, "LOUT1 Mixer"},
+       {"ROUT1", NULL, "ROUT1 Mixer"},
+       {"LOUT2", NULL, "LOUT2 Mix Amp"},
+       {"ROUT2", NULL, "ROUT2 Mix Amp"},
+       {"LOUT3", NULL, "LOUT3 Mixer"},
+       {"ROUT3", NULL, "ROUT3 Mixer"},
 
        {"LOUT1 Mixer", "DACL", "DAC Left"},
        {"ROUT1 Mixer", "DACR", "DAC Right"},
        {"LOUT2 Mixer", "DACHL", "DAC Left"},
        {"ROUT2 Mixer", "DACHR", "DAC Right"},
-       {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"},
-       {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"},
+       {"LOUT2 Mix Amp", NULL, "LOUT2 Mixer"},
+       {"ROUT2 Mix Amp", NULL, "ROUT2 Mixer"},
        {"LOUT3 Mixer", "DACSL", "DAC Left"},
        {"ROUT3 Mixer", "DACSR", "DAC Right"},
 
@@ -381,18 +381,18 @@ static const struct snd_soc_dapm_route ak4671_intercon[] = {
        {"LIN2", NULL, "Mic Bias"},
        {"RIN2", NULL, "Mic Bias"},
 
-       {"ADC Left", "NULL", "LIN MUX"},
-       {"ADC Right", "NULL", "RIN MUX"},
+       {"ADC Left", NULL, "LIN MUX"},
+       {"ADC Right", NULL, "RIN MUX"},
 
        /* Analog Loops */
-       {"LIN1 Mixing Circuit", "NULL", "LIN1"},
-       {"RIN1 Mixing Circuit", "NULL", "RIN1"},
-       {"LIN2 Mixing Circuit", "NULL", "LIN2"},
-       {"RIN2 Mixing Circuit", "NULL", "RIN2"},
-       {"LIN3 Mixing Circuit", "NULL", "LIN3"},
-       {"RIN3 Mixing Circuit", "NULL", "RIN3"},
-       {"LIN4 Mixing Circuit", "NULL", "LIN4"},
-       {"RIN4 Mixing Circuit", "NULL", "RIN4"},
+       {"LIN1 Mixing Circuit", NULL, "LIN1"},
+       {"RIN1 Mixing Circuit", NULL, "RIN1"},
+       {"LIN2 Mixing Circuit", NULL, "LIN2"},
+       {"RIN2 Mixing Circuit", NULL, "RIN2"},
+       {"LIN3 Mixing Circuit", NULL, "LIN3"},
+       {"RIN3 Mixing Circuit", NULL, "RIN3"},
+       {"LIN4 Mixing Circuit", NULL, "LIN4"},
+       {"RIN4 Mixing Circuit", NULL, "RIN4"},
 
        {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"},
        {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"},
index f2b8aad..60598b2 100644 (file)
@@ -437,20 +437,13 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
        }
 
        /* Reset the Device */
-       cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev,
-               "reset-gpios");
-       if (IS_ERR(cs35l32->reset_gpio)) {
-               ret = PTR_ERR(cs35l32->reset_gpio);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               cs35l32->reset_gpio = NULL;
-       } else {
-               ret = gpiod_direction_output(cs35l32->reset_gpio, 0);
-               if (ret)
-                       return ret;
+       cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+               "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(cs35l32->reset_gpio))
+               return PTR_ERR(cs35l32->reset_gpio);
+
+       if (cs35l32->reset_gpio)
                gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
-       }
 
        /* initialize codec */
        ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, &reg);
index ce60868..cac48dd 100644 (file)
@@ -605,21 +605,14 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
                return ret;
        }
 
-       cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev,
-               "reset-gpios");
-       if (IS_ERR(cs4265->reset_gpio)) {
-               ret = PTR_ERR(cs4265->reset_gpio);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               cs4265->reset_gpio = NULL;
-       } else {
-               ret = gpiod_direction_output(cs4265->reset_gpio, 0);
-               if (ret)
-                       return ret;
+       cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+               "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(cs4265->reset_gpio))
+               return PTR_ERR(cs4265->reset_gpio);
+
+       if (cs4265->reset_gpio) {
                mdelay(1);
                gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
-
        }
 
        i2c_set_clientdata(i2c_client, cs4265);
index 79a4efc..e770ee6 100644 (file)
@@ -286,7 +286,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = cs4271->deemph;
+       ucontrol->value.integer.value[0] = cs4271->deemph;
        return 0;
 }
 
@@ -296,7 +296,7 @@ static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
 
-       cs4271->deemph = ucontrol->value.enumerated.item[0];
+       cs4271->deemph = ucontrol->value.integer.value[0];
        return cs4271_set_deemph(codec);
 }
 
@@ -561,10 +561,10 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec)
        if (gpio_is_valid(cs4271->gpio_nreset)) {
                /* Reset codec */
                gpio_direction_output(cs4271->gpio_nreset, 0);
-               udelay(1);
+               mdelay(1);
                gpio_set_value(cs4271->gpio_nreset, 1);
                /* Give the codec time to wake up */
-               udelay(1);
+               mdelay(1);
        }
 
        ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
index ffe9617..911c26c 100644 (file)
@@ -876,11 +876,11 @@ static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route da732x_dapm_routes[] = {
        /* Inputs */
-       {"AUX1L PGA", "NULL", "AUX1L"},
-       {"AUX1R PGA", "NULL", "AUX1R"},
+       {"AUX1L PGA", NULL, "AUX1L"},
+       {"AUX1R PGA", NULL, "AUX1R"},
        {"MIC1 PGA", NULL, "MIC1"},
-       {"MIC2 PGA", "NULL", "MIC2"},
-       {"MIC3 PGA", "NULL", "MIC3"},
+       {"MIC2 PGA", NULL, "MIC2"},
+       {"MIC3 PGA", NULL, "MIC3"},
 
        /* Capture Path */
        {"ADC1 Left MUX", "MIC1", "MIC1 PGA"},
index f273251..c5f35a0 100644 (file)
@@ -120,7 +120,7 @@ static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = es8328->deemph;
+       ucontrol->value.integer.value[0] = es8328->deemph;
        return 0;
 }
 
@@ -129,7 +129,7 @@ static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret;
 
        if (deemph > 1)
index 1806333..bf3e933 100644 (file)
  * max98357a.c -- MAX98357A ALSA SoC Codec driver
  */
 
-#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
 #include <sound/soc.h>
-
-#define DRV_NAME "max98357a"
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
 
 static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
                int cmd, struct snd_soc_dai *dai)
@@ -77,9 +85,9 @@ static struct snd_soc_dai_ops max98357a_dai_ops = {
 };
 
 static struct snd_soc_dai_driver max98357a_dai_driver = {
-       .name = DRV_NAME,
+       .name = "HiFi",
        .playback = {
-               .stream_name    = DRV_NAME "-playback",
+               .stream_name    = "HiFi Playback",
                .formats        = SNDRV_PCM_FMTBIT_S16 |
                                        SNDRV_PCM_FMTBIT_S24 |
                                        SNDRV_PCM_FMTBIT_S32,
@@ -117,7 +125,7 @@ static int max98357a_platform_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_OF
 static const struct of_device_id max98357a_device_id[] = {
-       { .compatible = "maxim," DRV_NAME, },
+       { .compatible = "maxim,max98357a" },
        {}
 };
 MODULE_DEVICE_TABLE(of, max98357a_device_id);
@@ -125,7 +133,7 @@ MODULE_DEVICE_TABLE(of, max98357a_device_id);
 
 static struct platform_driver max98357a_platform_driver = {
        .driver = {
-               .name = DRV_NAME,
+               .name = "max98357a",
                .of_match_table = of_match_ptr(max98357a_device_id),
        },
        .probe  = max98357a_platform_probe,
@@ -135,4 +143,3 @@ module_platform_driver(max98357a_platform_driver);
 
 MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRV_NAME);
index a722a02..477e13d 100644 (file)
@@ -118,7 +118,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = priv->deemph;
+       ucontrol->value.integer.value[0] = priv->deemph;
 
        return 0;
 }
@@ -129,7 +129,7 @@ static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       priv->deemph = ucontrol->value.enumerated.item[0];
+       priv->deemph = ucontrol->value.integer.value[0];
 
        return pcm1681_set_deemph(codec);
 }
index 9974f20..5a30fdd 100644 (file)
@@ -54,6 +54,9 @@ struct pcm512x_priv {
        int pll_d;
        int pll_p;
        unsigned long real_pll;
+       unsigned long overclock_pll;
+       unsigned long overclock_dac;
+       unsigned long overclock_dsp;
 };
 
 /*
@@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
        }
 }
 
+static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = pcm512x->overclock_pll;
+       return 0;
+}
+
+static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       switch (codec->dapm.bias_level) {
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_STANDBY:
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       pcm512x->overclock_pll = ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = pcm512x->overclock_dsp;
+       return 0;
+}
+
+static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       switch (codec->dapm.bias_level) {
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_STANDBY:
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       pcm512x->overclock_dsp = ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = pcm512x->overclock_dac;
+       return 0;
+}
+
+static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       switch (codec->dapm.bias_level) {
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_STANDBY:
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       pcm512x->overclock_dac = ucontrol->value.integer.value[0];
+       return 0;
+}
+
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
 static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
 static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
@@ -304,9 +391,9 @@ static const struct soc_enum pcm512x_veds =
 static const struct snd_kcontrol_new pcm512x_controls[] = {
 SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
                 PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
-SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
+SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
               PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
-SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
               PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
 SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
           PCM512x_RQMR_SHIFT, 1, 1),
@@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf),
 SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus),
 SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf),
 SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds),
+
+SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0,
+              pcm512x_overclock_pll_get, pcm512x_overclock_pll_put),
+SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0,
+              pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put),
+SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0,
+              pcm512x_overclock_dac_get, pcm512x_overclock_dac_put),
 };
 
 static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = {
@@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
        { "OUTR", NULL, "DACR" },
 };
 
+static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x)
+{
+       return 25000000 + 25000000 * pcm512x->overclock_pll / 100;
+}
+
+static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x)
+{
+       return 50000000 + 50000000 * pcm512x->overclock_dsp / 100;
+}
+
+static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x,
+                                    unsigned long rate)
+{
+       return rate + rate * pcm512x->overclock_dac / 100;
+}
+
+static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x)
+{
+       if (!pcm512x->pll_out)
+               return 25000000;
+       return pcm512x_pll_max(pcm512x);
+}
+
+static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x,
+                                       unsigned long dac_rate)
+{
+       /*
+        * If the DAC is not actually overclocked, use the good old
+        * NCP target rate...
+        */
+       if (dac_rate <= 6144000)
+               return 1536000;
+       /*
+        * ...but if the DAC is in fact overclocked, bump the NCP target
+        * rate to get the recommended dividers even when overclocking.
+        */
+       return pcm512x_dac_max(pcm512x, 1536000);
+}
+
 static const u32 pcm512x_dai_rates[] = {
        8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
        88200, 96000, 176400, 192000, 384000,
@@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = {
 static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
                                struct snd_pcm_hw_rule *rule)
 {
+       struct pcm512x_priv *pcm512x = rule->private;
        struct snd_interval ranges[2];
        int frame_size;
 
@@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
                 */
                memset(ranges, 0, sizeof(ranges));
                ranges[0].min = 8000;
-               ranges[0].max = 25000000 / frame_size / 2;
+               ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2;
                ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
                ranges[1].max = 384000;
                break;
@@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
                return snd_pcm_hw_rule_add(substream->runtime, 0,
                                           SNDRV_PCM_HW_PARAM_RATE,
                                           pcm512x_hw_rule_rate,
-                                          NULL,
+                                          pcm512x,
                                           SNDRV_PCM_HW_PARAM_FRAME_BITS,
                                           SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
@@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
                                      unsigned long bclk_rate)
 {
        struct device *dev = dai->dev;
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
        unsigned long sck_rate;
        int pow2;
 
@@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
         * as many factors of 2 as possible, as that makes it easier
         * to find a fast DAC rate
         */
-       pow2 = 1 << fls((25000000 - 16000000) / bclk_rate);
+       pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate);
        for (; pow2; pow2 >>= 1) {
-               sck_rate = rounddown(25000000, bclk_rate * pow2);
+               sck_rate = rounddown(pcm512x_pll_max(pcm512x),
+                                    bclk_rate * pow2);
                if (sck_rate >= 16000000)
                        break;
        }
@@ -576,8 +713,8 @@ static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai,
 
        /* pllin_rate / P (or here, den) cannot be greater than 20 MHz */
        if (pllin_rate / den > 20000000 && num < 8) {
-               num *= 20000000 / (pllin_rate / den);
-               den *= 20000000 / (pllin_rate / den);
+               num *= DIV_ROUND_UP(pllin_rate / den, 20000000);
+               den *= DIV_ROUND_UP(pllin_rate / den, 20000000);
        }
        dev_dbg(dev, "num / den = %lu / %lu\n", num, den);
 
@@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
                return 0; /* futile, quit early */
 
        /* run DAC no faster than 6144000 Hz */
-       for (dac_rate = rounddown(6144000, osr_rate);
+       for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate);
             dac_rate;
             dac_rate -= osr_rate) {
 
@@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
        osr_rate = 16 * sample_rate;
 
        /* run DSP no faster than 50 MHz */
-       dsp_div = mck_rate > 50000000 ? 2 : 1;
+       dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1;
 
        dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
        if (dac_rate) {
@@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
                dacsrc_rate = pllin_rate;
        } else {
                /* run DAC no faster than 6144000 Hz */
-               unsigned long dac_mul = 6144000 / osr_rate;
+               unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000)
+                       / osr_rate;
                unsigned long sck_mul = sck_rate / osr_rate;
 
                for (; dac_mul; dac_mul--) {
@@ -863,28 +1001,30 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
                dacsrc_rate = sck_rate;
        }
 
+       osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
+       if (osr_div > 128) {
+               dev_err(dev, "Failed to find OSR divider\n");
+               return -EINVAL;
+       }
+
        dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
        if (dac_div > 128) {
                dev_err(dev, "Failed to find DAC divider\n");
                return -EINVAL;
        }
+       dac_rate = dacsrc_rate / dac_div;
 
-       ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000);
-       if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) {
+       ncp_div = DIV_ROUND_CLOSEST(dac_rate,
+                                   pcm512x_ncp_target(pcm512x, dac_rate));
+       if (ncp_div > 128 || dac_rate / ncp_div > 2048000) {
                /* run NCP no faster than 2048000 Hz, but why? */
-               ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000);
+               ncp_div = DIV_ROUND_UP(dac_rate, 2048000);
                if (ncp_div > 128) {
                        dev_err(dev, "Failed to find NCP divider\n");
                        return -EINVAL;
                }
        }
 
-       osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
-       if (osr_div > 128) {
-               dev_err(dev, "Failed to find OSR divider\n");
-               return -EINVAL;
-       }
-
        idac = mck_rate / (dsp_div * sample_rate);
 
        ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
@@ -937,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
                return ret;
        }
 
-       if (sample_rate <= 48000)
+       if (sample_rate <= pcm512x_dac_max(pcm512x, 48000))
                fssp = PCM512x_FSSP_48KHZ;
-       else if (sample_rate <= 96000)
+       else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000))
                fssp = PCM512x_FSSP_96KHZ;
-       else if (sample_rate <= 192000)
+       else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000))
                fssp = PCM512x_FSSP_192KHZ;
        else
                fssp = PCM512x_FSSP_384KHZ;
@@ -1156,25 +1296,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
                                ret, pcm512x->pll_out);
                        return ret;
                }
-
-               gpio = PCM512x_G1OE << (4 - 1);
-               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
-                                        gpio, gpio);
-               if (ret != 0) {
-                       dev_err(codec->dev, "Failed to enable gpio %d: %d\n",
-                               4, ret);
-                       return ret;
-               }
-
-               gpio = PCM512x_GPIO_OUTPUT_1 + 4 - 1;
-               ret = regmap_update_bits(pcm512x->regmap, gpio,
-                                        PCM512x_GxSL, PCM512x_GxSL_PLLLK);
-               if (ret != 0) {
-                       dev_err(codec->dev,
-                               "Failed to output pll lock on %d: %d\n",
-                               ret, 4);
-                       return ret;
-               }
        }
 
        ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
index f374840..8260370 100644 (file)
@@ -395,9 +395,20 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 
        rt286->jack = jack;
 
-       /* Send an initial empty report */
-       snd_soc_jack_report(rt286->jack, 0,
-               SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+       if (jack) {
+               /* enable IRQ */
+               if (rt286->jack->status | SND_JACK_HEADPHONE)
+                       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1");
+               regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
+               /* Send an initial empty report */
+               snd_soc_jack_report(rt286->jack, rt286->jack->status,
+                       SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+       } else {
+               /* disable IRQ */
+               regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
+               snd_soc_dapm_disable_pin(&codec->dapm, "LDO1");
+       }
+       snd_soc_dapm_sync(&codec->dapm);
 
        return 0;
 }
@@ -1198,7 +1209,7 @@ static struct dmi_system_id dmi_dell_dino[] = {
                .ident = "Dell Dino",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_BOARD_NAME, "0144P8")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343")
                }
        },
        { }
index c9a4c5b..69528ae 100644 (file)
@@ -1270,6 +1270,8 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
                        snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
                                RT5645_PWR_HP_L | RT5645_PWR_HP_R |
                                RT5645_PWR_HA, 0);
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+                               RT5645_DEPOP_MASK, 0);
                }
        }
 }
@@ -1538,8 +1540,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
 
        SND_SOC_DAPM_SUPPLY_S("adc stereo1 filter", 1, RT5645_PWR_DIG2,
                RT5645_PWR_ADC_S1F_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY_S("adc stereo2 filter", 1, RT5645_PWR_DIG2,
-               RT5645_PWR_ADC_S2F_BIT, 0, NULL, 0),
        SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
                rt5645_sto1_adc_l_mix, ARRAY_SIZE(rt5645_sto1_adc_l_mix),
                NULL, 0),
@@ -1729,7 +1729,6 @@ static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
-       { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
        { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
        { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
        { "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc },
@@ -2052,7 +2051,7 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val_len = 0, val_clk, mask_clk;
+       unsigned int val_len = 0, val_clk, mask_clk, dl_sft;
        int pre_div, bclk_ms, frame_size;
 
        rt5645->lrck[dai->id] = params_rate(params);
@@ -2066,6 +2065,16 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
                dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
                return -EINVAL;
        }
+
+       switch (rt5645->codec_type) {
+       case CODEC_TYPE_RT5650:
+               dl_sft = 4;
+               break;
+       default:
+               dl_sft = 2;
+               break;
+       }
+
        bclk_ms = frame_size > 32;
        rt5645->bclk[dai->id] = rt5645->lrck[dai->id] * (32 << bclk_ms);
 
@@ -2078,13 +2087,13 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
        case 16:
                break;
        case 20:
-               val_len |= RT5645_I2S_DL_20;
+               val_len = 0x1;
                break;
        case 24:
-               val_len |= RT5645_I2S_DL_24;
+               val_len = 0x2;
                break;
        case 8:
-               val_len |= RT5645_I2S_DL_8;
+               val_len = 0x3;
                break;
        default:
                return -EINVAL;
@@ -2096,7 +2105,7 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
                val_clk = bclk_ms << RT5645_I2S_BCLK_MS1_SFT |
                        pre_div << RT5645_I2S_PD1_SFT;
                snd_soc_update_bits(codec, RT5645_I2S1_SDP,
-                       RT5645_I2S_DL_MASK, val_len);
+                       (0x3 << dl_sft), (val_len << dl_sft));
                snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
                break;
        case  RT5645_AIF2:
@@ -2104,7 +2113,7 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
                val_clk = bclk_ms << RT5645_I2S_BCLK_MS2_SFT |
                        pre_div << RT5645_I2S_PD2_SFT;
                snd_soc_update_bits(codec, RT5645_I2S2_SDP,
-                       RT5645_I2S_DL_MASK, val_len);
+                       (0x3 << dl_sft), (val_len << dl_sft));
                snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
                break;
        default:
@@ -2119,7 +2128,16 @@ static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct snd_soc_codec *codec = dai->codec;
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
-       unsigned int reg_val = 0;
+       unsigned int reg_val = 0, pol_sft;
+
+       switch (rt5645->codec_type) {
+       case CODEC_TYPE_RT5650:
+               pol_sft = 8;
+               break;
+       default:
+               pol_sft = 7;
+               break;
+       }
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
@@ -2137,7 +2155,7 @@ static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        case SND_SOC_DAIFMT_NB_NF:
                break;
        case SND_SOC_DAIFMT_IB_NF:
-               reg_val |= RT5645_I2S_BP_INV;
+               reg_val |= (1 << pol_sft);
                break;
        default:
                return -EINVAL;
@@ -2161,12 +2179,12 @@ static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (dai->id) {
        case RT5645_AIF1:
                snd_soc_update_bits(codec, RT5645_I2S1_SDP,
-                       RT5645_I2S_MS_MASK | RT5645_I2S_BP_MASK |
+                       RT5645_I2S_MS_MASK | (1 << pol_sft) |
                        RT5645_I2S_DF_MASK, reg_val);
                break;
        case RT5645_AIF2:
                snd_soc_update_bits(codec, RT5645_I2S2_SDP,
-                       RT5645_I2S_MS_MASK | RT5645_I2S_BP_MASK |
+                       RT5645_I2S_MS_MASK | (1 << pol_sft) |
                        RT5645_I2S_DF_MASK, reg_val);
                break;
        default:
@@ -2285,23 +2303,42 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
                        unsigned int rx_mask, int slots, int slot_width)
 {
        struct snd_soc_codec *codec = dai->codec;
-       unsigned int val = 0;
+       struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+       unsigned int i_slot_sft, o_slot_sft, i_width_sht, o_width_sht, en_sft;
+       unsigned int mask, val = 0;
 
+       switch (rt5645->codec_type) {
+       case CODEC_TYPE_RT5650:
+               en_sft = 15;
+               i_slot_sft = 10;
+               o_slot_sft = 8;
+               i_width_sht = 6;
+               o_width_sht = 4;
+               mask = 0x8ff0;
+               break;
+       default:
+               en_sft = 14;
+               i_slot_sft = o_slot_sft = 12;
+               i_width_sht = o_width_sht = 10;
+               mask = 0x7c00;
+               break;
+       }
        if (rx_mask || tx_mask) {
-               val |= (1 << 14);
-               snd_soc_update_bits(codec, RT5645_BASS_BACK,
-                       RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB);
+               val |= (1 << en_sft);
+               if (rt5645->codec_type == CODEC_TYPE_RT5645)
+                       snd_soc_update_bits(codec, RT5645_BASS_BACK,
+                               RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB);
        }
 
        switch (slots) {
        case 4:
-               val |= (1 << 12);
+               val |= (1 << i_slot_sft) | (1 << o_slot_sft);
                break;
        case 6:
-               val |= (2 << 12);
+               val |= (2 << i_slot_sft) | (2 << o_slot_sft);
                break;
        case 8:
-               val |= (3 << 12);
+               val |= (3 << i_slot_sft) | (3 << o_slot_sft);
                break;
        case 2:
        default:
@@ -2310,20 +2347,20 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 
        switch (slot_width) {
        case 20:
-               val |= (1 << 10);
+               val |= (1 << i_width_sht) | (1 << o_width_sht);
                break;
        case 24:
-               val |= (2 << 10);
+               val |= (2 << i_width_sht) | (2 << o_width_sht);
                break;
        case 32:
-               val |= (3 << 10);
+               val |= (3 << i_width_sht) | (3 << o_width_sht);
                break;
        case 16:
        default:
                break;
        }
 
-       snd_soc_update_bits(codec, RT5645_TDM_CTRL_1, 0x7c00, val);
+       snd_soc_update_bits(codec, RT5645_TDM_CTRL_1, mask, val);
 
        return 0;
 }
@@ -2361,7 +2398,8 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_OFF:
                snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
-               snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128);
+               snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
+                               RT5645_DIG_GATE_CTRL, 0);
                snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
                                RT5645_PWR_VREF1 | RT5645_PWR_MB |
                                RT5645_PWR_BG | RT5645_PWR_VREF2 |
@@ -2598,7 +2636,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5645 = {
 static const struct regmap_config rt5645_regmap = {
        .reg_bits = 8,
        .val_bits = 16,
-
+       .use_single_rw = true,
        .max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) *
                                               RT5645_PR_SPACING),
        .volatile_reg = rt5645_volatile_register,
index dbfd98c..db78e94 100644 (file)
 #define RT5645_PWR_DAC_MF_L_BIT                        10
 #define RT5645_PWR_DAC_MF_R                    (0x1 << 9)
 #define RT5645_PWR_DAC_MF_R_BIT                        9
-#define RT5645_PWR_ADC_S2F                     (0x1 << 8)
-#define RT5645_PWR_ADC_S2F_BIT                 8
 #define RT5645_PWR_PDM1                                (0x1 << 7)
 #define RT5645_PWR_PDM1_BIT                    7
 #define RT5645_PWR_PDM2                                (0x1 << 6)
index e1a4a45..cc7f84a 100644 (file)
@@ -225,7 +225,6 @@ static bool rt5670_volatile_register(struct device *dev, unsigned int reg)
        case RT5670_ADC_EQ_CTRL1:
        case RT5670_EQ_CTRL1:
        case RT5670_ALC_CTRL_1:
-       case RT5670_IRQ_CTRL1:
        case RT5670_IRQ_CTRL2:
        case RT5670_INT_IRQ_ST:
        case RT5670_IL_CMD:
@@ -404,6 +403,189 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg)
        }
 }
 
+/**
+ * rt5670_headset_detect - Detect headset.
+ * @codec: SoC audio codec device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+
+static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+       int val;
+       struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+
+       if (jack_insert) {
+               snd_soc_dapm_force_enable_pin(&codec->dapm,
+                                                      "Mic Det Power");
+               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0);
+               snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
+                       RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD,
+                       RT5670_CBJ_MN_JD);
+               snd_soc_write(codec, RT5670_GPIO_CTRL2, 0x0004);
+               snd_soc_update_bits(codec, RT5670_GPIO_CTRL1,
+                       RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ);
+               snd_soc_update_bits(codec, RT5670_CJ_CTRL1,
+                       RT5670_CBJ_BST1_EN, RT5670_CBJ_BST1_EN);
+               snd_soc_write(codec, RT5670_JD_CTRL3, 0x00f0);
+               snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
+                       RT5670_CBJ_MN_JD, RT5670_CBJ_MN_JD);
+               snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
+                       RT5670_CBJ_MN_JD, 0);
+               msleep(300);
+               val = snd_soc_read(codec, RT5670_CJ_CTRL3) & 0x7;
+               if (val == 0x1 || val == 0x2) {
+                       rt5670->jack_type = SND_JACK_HEADSET;
+                       /* for push button */
+                       snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x8);
+                       snd_soc_update_bits(codec, RT5670_IL_CMD, 0x40, 0x40);
+                       snd_soc_read(codec, RT5670_IL_CMD);
+               } else {
+                       snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
+                       rt5670->jack_type = SND_JACK_HEADPHONE;
+                       snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
+                       snd_soc_dapm_sync(&codec->dapm);
+               }
+       } else {
+               snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0);
+               snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
+               rt5670->jack_type = 0;
+               snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
+               snd_soc_dapm_sync(&codec->dapm);
+       }
+
+       return rt5670->jack_type;
+}
+
+void rt5670_jack_suspend(struct snd_soc_codec *codec)
+{
+       struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+
+       rt5670->jack_type_saved = rt5670->jack_type;
+       rt5670_headset_detect(codec, 0);
+}
+EXPORT_SYMBOL_GPL(rt5670_jack_suspend);
+
+void rt5670_jack_resume(struct snd_soc_codec *codec)
+{
+       struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+
+       if (rt5670->jack_type_saved)
+               rt5670_headset_detect(codec, 1);
+}
+EXPORT_SYMBOL_GPL(rt5670_jack_resume);
+
+static int rt5670_button_detect(struct snd_soc_codec *codec)
+{
+       int btn_type, val;
+
+       val = snd_soc_read(codec, RT5670_IL_CMD);
+       btn_type = val & 0xff80;
+       snd_soc_write(codec, RT5670_IL_CMD, val);
+       if (btn_type != 0) {
+               msleep(20);
+               val = snd_soc_read(codec, RT5670_IL_CMD);
+               snd_soc_write(codec, RT5670_IL_CMD, val);
+       }
+
+       return btn_type;
+}
+
+static int rt5670_irq_detection(void *data)
+{
+       struct rt5670_priv *rt5670 = (struct rt5670_priv *)data;
+       struct snd_soc_jack_gpio *gpio = &rt5670->hp_gpio;
+       struct snd_soc_jack *jack = rt5670->jack;
+       int val, btn_type, report = jack->status;
+
+       if (rt5670->pdata.jd_mode == 1) /* 2 port */
+               val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0070;
+       else
+               val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0020;
+
+       switch (val) {
+       /* jack in */
+       case 0x30: /* 2 port */
+       case 0x0: /* 1 port or 2 port */
+               if (rt5670->jack_type == 0) {
+                       report = rt5670_headset_detect(rt5670->codec, 1);
+                       /* for push button and jack out */
+                       gpio->debounce_time = 25;
+                       break;
+               }
+               btn_type = 0;
+               if (snd_soc_read(rt5670->codec, RT5670_INT_IRQ_ST) & 0x4) {
+                       /* button pressed */
+                       report = SND_JACK_HEADSET;
+                       btn_type = rt5670_button_detect(rt5670->codec);
+                       switch (btn_type) {
+                       case 0x2000: /* up */
+                               report |= SND_JACK_BTN_1;
+                               break;
+                       case 0x0400: /* center */
+                               report |= SND_JACK_BTN_0;
+                               break;
+                       case 0x0080: /* down */
+                               report |= SND_JACK_BTN_2;
+                               break;
+                       default:
+                               dev_err(rt5670->codec->dev,
+                                       "Unexpected button code 0x%04x\n",
+                                       btn_type);
+                               break;
+                       }
+               }
+               if (btn_type == 0)/* button release */
+                       report =  rt5670->jack_type;
+
+               break;
+       /* jack out */
+       case 0x70: /* 2 port */
+       case 0x10: /* 2 port */
+       case 0x20: /* 1 port */
+               report = 0;
+               snd_soc_update_bits(rt5670->codec, RT5670_INT_IRQ_ST, 0x1, 0x0);
+               rt5670_headset_detect(rt5670->codec, 0);
+               gpio->debounce_time = 150; /* for jack in */
+               break;
+       default:
+               break;
+       }
+
+       return report;
+}
+
+int rt5670_set_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *jack)
+{
+       struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       rt5670->jack = jack;
+       rt5670->hp_gpio.gpiod_dev = codec->dev;
+       rt5670->hp_gpio.name = "headphone detect";
+       rt5670->hp_gpio.report = SND_JACK_HEADSET |
+               SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2;
+       rt5670->hp_gpio.debounce_time = 150;
+       rt5670->hp_gpio.wake = true;
+       rt5670->hp_gpio.data = (struct rt5670_priv *)rt5670;
+       rt5670->hp_gpio.jack_status_check = rt5670_irq_detection;
+
+       ret = snd_soc_jack_add_gpios(rt5670->jack, 1,
+                       &rt5670->hp_gpio);
+       if (ret) {
+               dev_err(codec->dev, "Adding jack GPIO failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5670_set_jack_detect);
+
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
 static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
@@ -518,11 +700,9 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-       unsigned int val;
+       struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
-       val = snd_soc_read(codec, RT5670_GLB_CLK);
-       val &= RT5670_SCLK_SRC_MASK;
-       if (val == RT5670_SCLK_SRC_PLL1)
+       if (rt5670->sysclk_src == RT5670_SCLK_S_PLL1)
                return 1;
        else
                return 0;
@@ -2272,16 +2452,6 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai,
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
        unsigned int reg_val = 0;
 
-       if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src)
-               return 0;
-
-       if (rt5670->pdata.jd_mode) {
-               if (clk_id == RT5670_SCLK_S_PLL1)
-                       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
-               else
-                       snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
-               snd_soc_dapm_sync(&codec->dapm);
-       }
        switch (clk_id) {
        case RT5670_SCLK_S_MCLK:
                reg_val |= RT5670_SCLK_SRC_MCLK;
@@ -2299,7 +2469,8 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai,
        snd_soc_update_bits(codec, RT5670_GLB_CLK,
                RT5670_SCLK_SRC_MASK, reg_val);
        rt5670->sysclk = freq;
-       rt5670->sysclk_src = clk_id;
+       if (clk_id != RT5670_SCLK_S_RCCLK)
+               rt5670->sysclk_src = clk_id;
 
        dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
 
@@ -2518,6 +2689,7 @@ static int rt5670_remove(struct snd_soc_codec *codec)
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
        regmap_write(rt5670->regmap, RT5670_RESET, 0);
+       snd_soc_jack_free_gpios(rt5670->jack, 1, &rt5670->hp_gpio);
        return 0;
 }
 
@@ -2677,6 +2849,7 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
        if (dmi_check_system(dmi_platform_intel_braswell)) {
                rt5670->pdata.dmic_en = true;
                rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+               rt5670->pdata.dev_gpio = true;
                rt5670->pdata.jd_mode = 1;
        }
 
@@ -2703,6 +2876,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
 
        regmap_write(rt5670->regmap, RT5670_RESET, 0);
 
+       regmap_read(rt5670->regmap, RT5670_VENDOR_ID, &val);
+       if (val >= 4)
+               regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0980);
+       else
+               regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0d00);
+
        ret = regmap_register_patch(rt5670->regmap, init_list,
                                    ARRAY_SIZE(init_list));
        if (ret != 0)
@@ -2712,12 +2891,17 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
                regmap_update_bits(rt5670->regmap, RT5670_IN2,
                                        RT5670_IN_DF2, RT5670_IN_DF2);
 
-       if (i2c->irq) {
+       if (rt5670->pdata.dev_gpio) {
+               /* for push button */
+               regmap_write(rt5670->regmap, RT5670_IL_CMD, 0x0000);
+               regmap_write(rt5670->regmap, RT5670_IL_CMD2, 0x0010);
+               regmap_write(rt5670->regmap, RT5670_IL_CMD3, 0x0014);
+               /* for irq */
                regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1,
                                   RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ);
                regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2,
                                   RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT);
-
+               regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8);
        }
 
        if (rt5670->pdata.jd_mode) {
index 21f8e18..dc2b462 100644 (file)
@@ -1950,17 +1950,20 @@ enum {
 };
 
 enum {
+       RT5670_DMIC1_DISABLED,
        RT5670_DMIC_DATA_GPIO6,
        RT5670_DMIC_DATA_IN2P,
        RT5670_DMIC_DATA_GPIO7,
 };
 
 enum {
+       RT5670_DMIC2_DISABLED,
        RT5670_DMIC_DATA_GPIO8,
        RT5670_DMIC_DATA_IN3N,
 };
 
 enum {
+       RT5670_DMIC3_DISABLED,
        RT5670_DMIC_DATA_GPIO9,
        RT5670_DMIC_DATA_GPIO10,
        RT5670_DMIC_DATA_GPIO5,
@@ -1985,6 +1988,8 @@ struct rt5670_priv {
        struct snd_soc_codec *codec;
        struct rt5670_platform_data pdata;
        struct regmap *regmap;
+       struct snd_soc_jack *jack;
+       struct snd_soc_jack_gpio hp_gpio;
 
        int sysclk;
        int sysclk_src;
@@ -1999,6 +2004,11 @@ struct rt5670_priv {
        int dsp_sw; /* expected parameter setting */
        int dsp_rate;
        int jack_type;
+       int jack_type_saved;
 };
 
+void rt5670_jack_suspend(struct snd_soc_codec *codec);
+void rt5670_jack_resume(struct snd_soc_codec *codec);
+int rt5670_set_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *jack);
 #endif /* __RT5670_H__ */
index 5d0bb87..c2a6e40 100644 (file)
@@ -718,11 +718,24 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
                        RT5677_LDO1_SEL_MASK, 0x0);
                regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
                        RT5677_PWR_LDO1, RT5677_PWR_LDO1);
-               regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
-                       RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
-               regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
-                       RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK,
-                       RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS);
+               switch (rt5677->type) {
+               case RT5677:
+                       regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+                               RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
+                       regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
+                               RT5677_PLL2_PR_SRC_MASK |
+                               RT5677_DSP_CLK_SRC_MASK,
+                               RT5677_PLL2_PR_SRC_MCLK2 |
+                               RT5677_DSP_CLK_SRC_BYPASS);
+                       break;
+               case RT5676:
+                       regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
+                               RT5677_DSP_CLK_SRC_MASK,
+                               RT5677_DSP_CLK_SRC_BYPASS);
+                       break;
+               default:
+                       break;
+               }
                regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff);
                regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd);
                rt5677_set_dsp_mode(codec, true);
@@ -3284,8 +3297,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "IB45 Bypass Mux", "Bypass", "IB45 Mux" },
        { "IB45 Bypass Mux", "Pass SRC", "IB45 Mux" },
 
-       { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6" },
-       { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6" },
+       { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6 Mux" },
+       { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6 Mux" },
        { "IB6 Mux", "SLB DAC 6", "SLB DAC6" },
        { "IB6 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" },
        { "IB6 Mux", "IF4 DAC L", "IF4 DAC L" },
@@ -3293,8 +3306,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "IB6 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" },
        { "IB6 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" },
 
-       { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7" },
-       { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7" },
+       { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7 Mux" },
+       { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7 Mux" },
        { "IB7 Mux", "SLB DAC 7", "SLB DAC7" },
        { "IB7 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" },
        { "IB7 Mux", "IF4 DAC R", "IF4 DAC R" },
@@ -3635,15 +3648,15 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "DAC1 FS", NULL, "DAC1 MIXL" },
        { "DAC1 FS", NULL, "DAC1 MIXR" },
 
-       { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2" },
-       { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2" },
+       { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2 Mux" },
+       { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2 Mux" },
        { "DAC2 L Mux", "IF3 DAC L", "IF3 DAC L" },
        { "DAC2 L Mux", "IF4 DAC L", "IF4 DAC L" },
        { "DAC2 L Mux", "SLB DAC 2", "SLB DAC2" },
        { "DAC2 L Mux", "OB 2", "OutBound2" },
 
-       { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3" },
-       { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3" },
+       { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3 Mux" },
+       { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3 Mux" },
        { "DAC2 R Mux", "IF3 DAC R", "IF3 DAC R" },
        { "DAC2 R Mux", "IF4 DAC R", "IF4 DAC R" },
        { "DAC2 R Mux", "SLB DAC 3", "SLB DAC3" },
@@ -3651,29 +3664,29 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "DAC2 R Mux", "Haptic Generator", "Haptic Generator" },
        { "DAC2 R Mux", "VAD ADC", "VAD ADC Mux" },
 
-       { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4" },
-       { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4" },
+       { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4 Mux" },
+       { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4 Mux" },
        { "DAC3 L Mux", "IF3 DAC L", "IF3 DAC L" },
        { "DAC3 L Mux", "IF4 DAC L", "IF4 DAC L" },
        { "DAC3 L Mux", "SLB DAC 4", "SLB DAC4" },
        { "DAC3 L Mux", "OB 4", "OutBound4" },
 
-       { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC4" },
-       { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC4" },
+       { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC5 Mux" },
+       { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC5 Mux" },
        { "DAC3 R Mux", "IF3 DAC R", "IF3 DAC R" },
        { "DAC3 R Mux", "IF4 DAC R", "IF4 DAC R" },
        { "DAC3 R Mux", "SLB DAC 5", "SLB DAC5" },
        { "DAC3 R Mux", "OB 5", "OutBound5" },
 
-       { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6" },
-       { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6" },
+       { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6 Mux" },
+       { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6 Mux" },
        { "DAC4 L Mux", "IF3 DAC L", "IF3 DAC L" },
        { "DAC4 L Mux", "IF4 DAC L", "IF4 DAC L" },
        { "DAC4 L Mux", "SLB DAC 6", "SLB DAC6" },
        { "DAC4 L Mux", "OB 6", "OutBound6" },
 
-       { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7" },
-       { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7" },
+       { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7 Mux" },
+       { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7 Mux" },
        { "DAC4 R Mux", "IF3 DAC R", "IF3 DAC R" },
        { "DAC4 R Mux", "IF4 DAC R", "IF4 DAC R" },
        { "DAC4 R Mux", "SLB DAC 7", "SLB DAC7" },
@@ -4500,10 +4513,10 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
        if (!rt5677->dsp_vad_en) {
                regcache_cache_only(rt5677->regmap, true);
                regcache_mark_dirty(rt5677->regmap);
-       }
 
-       if (gpio_is_valid(rt5677->pow_ldo2))
-               gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+               if (gpio_is_valid(rt5677->pow_ldo2))
+                       gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+       }
 
        return 0;
 }
@@ -4512,12 +4525,12 @@ static int rt5677_resume(struct snd_soc_codec *codec)
 {
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
-       if (gpio_is_valid(rt5677->pow_ldo2)) {
-               gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
-               msleep(10);
-       }
-
        if (!rt5677->dsp_vad_en) {
+               if (gpio_is_valid(rt5677->pow_ldo2)) {
+                       gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
+                       msleep(10);
+               }
+
                regcache_cache_only(rt5677->regmap, false);
                regcache_sync(rt5677->regmap);
        }
@@ -4733,7 +4746,8 @@ static const struct regmap_config rt5677_regmap = {
 };
 
 static const struct i2c_device_id rt5677_i2c_id[] = {
-       { "rt5677", 0 },
+       { "rt5677", RT5677 },
+       { "rt5676", RT5676 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
@@ -4850,6 +4864,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, rt5677);
 
+       rt5677->type = id->driver_data;
+
        if (pdata)
                rt5677->pdata = *pdata;
 
index c0a625f..07df96b 100644 (file)
@@ -1665,6 +1665,11 @@ enum {
        RT5677_IRQ_JD3,
 };
 
+enum rt5677_type {
+       RT5677,
+       RT5676,
+};
+
 struct rt5677_priv {
        struct snd_soc_codec *codec;
        struct rt5677_platform_data pdata;
@@ -1681,6 +1686,7 @@ struct rt5677_priv {
        int pll_in;
        int pll_out;
        int pow_ldo2; /* POW_LDO2 pin */
+       enum rt5677_type type;
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip gpio_chip;
 #endif
index e182e65..3593a14 100644 (file)
@@ -1151,13 +1151,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
                /* Enable VDDC charge pump */
                ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP;
        } else if (vddio >= 3100 && vdda >= 3100) {
-               /*
-                * if vddio and vddd > 3.1v,
-                * charge pump should be clean before set ana_pwr
-                */
-               snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
-                               SGTL5000_VDDC_CHRGPMP_POWERUP, 0);
-
+               ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP;
                /* VDDC use VDDIO rail */
                lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
                lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO <<
index 47b257e..7947c0e 100644 (file)
@@ -538,8 +538,8 @@ static const struct snd_soc_dapm_route sn95031_audio_map[] = {
        /* speaker map */
        { "IHFOUTL", NULL, "Speaker Rail"},
        { "IHFOUTR", NULL, "Speaker Rail"},
-       { "IHFOUTL", "NULL", "Speaker Left Playback"},
-       { "IHFOUTR", "NULL", "Speaker Right Playback"},
+       { "IHFOUTL", NULL, "Speaker Left Playback"},
+       { "IHFOUTR", NULL, "Speaker Right Playback"},
        { "Speaker Left Playback", NULL, "Speaker Left Filter"},
        { "Speaker Right Playback", NULL, "Speaker Right Filter"},
        { "Speaker Left Filter", NULL, "IHFDAC Left"},
@@ -783,19 +783,21 @@ static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec)
        snd_soc_write(codec, SN95031_BTNCTRL2, 0x01);
 }
 
-static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack)
+static int sn95031_get_headset_state(struct snd_soc_codec *codec,
+       struct snd_soc_jack *mfld_jack)
 {
-       int micbias = sn95031_get_mic_bias(mfld_jack->codec);
+       int micbias = sn95031_get_mic_bias(codec);
 
        int jack_type = snd_soc_jack_get_type(mfld_jack, micbias);
 
        pr_debug("jack type detected = %d\n", jack_type);
        if (jack_type == SND_JACK_HEADSET)
-               sn95031_enable_jack_btn(mfld_jack->codec);
+               sn95031_enable_jack_btn(codec);
        return jack_type;
 }
 
-void sn95031_jack_detection(struct mfld_jack_data *jack_data)
+void sn95031_jack_detection(struct snd_soc_codec *codec,
+       struct mfld_jack_data *jack_data)
 {
        unsigned int status;
        unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET;
@@ -809,11 +811,11 @@ void sn95031_jack_detection(struct mfld_jack_data *jack_data)
                status = SND_JACK_HEADSET | SND_JACK_BTN_1;
        } else if (jack_data->intr_id & 0x4) {
                pr_debug("headset or headphones inserted\n");
-               status = sn95031_get_headset_state(jack_data->mfld_jack);
+               status = sn95031_get_headset_state(codec, jack_data->mfld_jack);
        } else if (jack_data->intr_id & 0x8) {
                pr_debug("headset or headphones removed\n");
                status = 0;
-               sn95031_disable_jack_btn(jack_data->mfld_jack->codec);
+               sn95031_disable_jack_btn(codec);
        } else {
                pr_err("unidentified interrupt\n");
                return;
index 20376d2..7651fe4 100644 (file)
@@ -127,6 +127,7 @@ struct mfld_jack_data {
        struct snd_soc_jack *mfld_jack;
 };
 
-extern void sn95031_jack_detection(struct mfld_jack_data *jack_data);
+extern void sn95031_jack_detection(struct snd_soc_codec *codec,
+       struct mfld_jack_data *jack_data);
 
 #endif
index 3a1343f..007a0e3 100644 (file)
@@ -106,13 +106,11 @@ static const struct reg_default sta32x_regs[] = {
 };
 
 static const struct regmap_range sta32x_write_regs_range[] = {
-       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
-       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+       regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
 };
 
 static const struct regmap_range sta32x_read_regs_range[] = {
-       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
-       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+       regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
 };
 
 static const struct regmap_range sta32x_volatile_regs_range[] = {
index bda2ee1..669e322 100644 (file)
@@ -1213,27 +1213,15 @@ static int sta350_i2c_probe(struct i2c_client *i2c,
 #endif
 
        /* GPIOs */
-       sta350->gpiod_nreset = devm_gpiod_get(dev, "reset");
-       if (IS_ERR(sta350->gpiod_nreset)) {
-               ret = PTR_ERR(sta350->gpiod_nreset);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               sta350->gpiod_nreset = NULL;
-       } else {
-               gpiod_direction_output(sta350->gpiod_nreset, 0);
-       }
-
-       sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down");
-       if (IS_ERR(sta350->gpiod_power_down)) {
-               ret = PTR_ERR(sta350->gpiod_power_down);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               sta350->gpiod_power_down = NULL;
-       } else {
-               gpiod_direction_output(sta350->gpiod_power_down, 0);
-       }
+       sta350->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
+                                                      GPIOD_OUT_LOW);
+       if (IS_ERR(sta350->gpiod_nreset))
+               return PTR_ERR(sta350->gpiod_nreset);
+
+       sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down",
+                                                 GPIOD_OUT_LOW);
+       if (IS_ERR(sta350->gpiod_power_down))
+               return PTR_ERR(sta350->gpiod_power_down);
 
        /* regulators */
        for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++)
index ae23acd..dfb4ff5 100644 (file)
@@ -485,16 +485,9 @@ static int tas2552_probe(struct i2c_client *client,
        if (data == NULL)
                return -ENOMEM;
 
-       data->enable_gpio = devm_gpiod_get(dev, "enable");
-       if (IS_ERR(data->enable_gpio)) {
-               ret = PTR_ERR(data->enable_gpio);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               data->enable_gpio = NULL;
-       } else {
-               gpiod_direction_output(data->enable_gpio, 0);
-       }
+       data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+       if (IS_ERR(data->enable_gpio))
+               return PTR_ERR(data->enable_gpio);
 
        data->tas2552_client = client;
        data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
index 249ef5c..32942be 100644 (file)
@@ -281,7 +281,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = priv->deemph;
+       ucontrol->value.integer.value[0] = priv->deemph;
 
        return 0;
 }
@@ -292,7 +292,7 @@ static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       priv->deemph = ucontrol->value.enumerated.item[0];
+       priv->deemph = ucontrol->value.integer.value[0];
 
        return tas5086_set_deemph(codec);
 }
index 8d9de49..21d5402 100644 (file)
@@ -610,7 +610,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ucontrol->value.enumerated.item[0] = wm2000->anc_active;
+       ucontrol->value.integer.value[0] = wm2000->anc_active;
 
        return 0;
 }
@@ -620,7 +620,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int anc_active = ucontrol->value.enumerated.item[0];
+       int anc_active = ucontrol->value.integer.value[0];
        int ret;
 
        if (anc_active > 1)
@@ -643,7 +643,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ucontrol->value.enumerated.item[0] = wm2000->spk_ena;
+       ucontrol->value.integer.value[0] = wm2000->spk_ena;
 
        return 0;
 }
@@ -653,7 +653,7 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int val = ucontrol->value.enumerated.item[0];
+       int val = ucontrol->value.integer.value[0];
        int ret;
 
        if (val > 1)
index c81a9ea..c65e5a7 100644 (file)
@@ -69,14 +69,14 @@ struct wm8350_data {
        struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
        int fll_freq_out;
        int fll_freq_in;
+       struct delayed_work pga_work;
 };
 
 /*
  * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown.
  */
-static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec)
+static inline int wm8350_out1_ramp_step(struct wm8350_data *wm8350_data)
 {
-       struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out1 = &wm8350_data->out1;
        struct wm8350 *wm8350 = wm8350_data->wm8350;
        int left_complete = 0, right_complete = 0;
@@ -140,9 +140,8 @@ static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec)
 /*
  * Ramp OUT2 PGA volume to minimise pops at stream startup and shutdown.
  */
-static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
+static inline int wm8350_out2_ramp_step(struct wm8350_data *wm8350_data)
 {
-       struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out2 = &wm8350_data->out2;
        struct wm8350 *wm8350 = wm8350_data->wm8350;
        int left_complete = 0, right_complete = 0;
@@ -210,10 +209,8 @@ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
  */
 static void wm8350_pga_work(struct work_struct *work)
 {
-       struct snd_soc_dapm_context *dapm =
-           container_of(work, struct snd_soc_dapm_context, delayed_work.work);
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-       struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+       struct wm8350_data *wm8350_data =
+               container_of(work, struct wm8350_data, pga_work.work);
        struct wm8350_output *out1 = &wm8350_data->out1,
            *out2 = &wm8350_data->out2;
        int i, out1_complete, out2_complete;
@@ -226,9 +223,9 @@ static void wm8350_pga_work(struct work_struct *work)
        for (i = 0; i <= 63; i++) {
                out1_complete = 1, out2_complete = 1;
                if (out1->ramp != WM8350_RAMP_NONE)
-                       out1_complete = wm8350_out1_ramp_step(codec);
+                       out1_complete = wm8350_out1_ramp_step(wm8350_data);
                if (out2->ramp != WM8350_RAMP_NONE)
-                       out2_complete = wm8350_out2_ramp_step(codec);
+                       out2_complete = wm8350_out2_ramp_step(wm8350_data);
 
                /* ramp finished ? */
                if (out1_complete && out2_complete)
@@ -283,7 +280,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,
                out->ramp = WM8350_RAMP_UP;
                out->active = 1;
 
-               schedule_delayed_work(&codec->dapm.delayed_work,
+               schedule_delayed_work(&wm8350_data->pga_work,
                                      msecs_to_jiffies(1));
                break;
 
@@ -291,7 +288,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,
                out->ramp = WM8350_RAMP_DOWN;
                out->active = 0;
 
-               schedule_delayed_work(&codec->dapm.delayed_work,
+               schedule_delayed_work(&wm8350_data->pga_work,
                                      msecs_to_jiffies(1));
                break;
        }
@@ -1492,7 +1489,7 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
        /* Put the codec into reset if it wasn't already */
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
-       INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work);
+       INIT_DELAYED_WORK(&priv->pga_work, wm8350_pga_work);
        INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work);
        INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work);
 
@@ -1578,7 +1575,7 @@ static int  wm8350_codec_remove(struct snd_soc_codec *codec)
 
        /* if there was any work waiting then we run it now and
         * wait for its completion */
-       flush_delayed_work(&codec->dapm.delayed_work);
+       flush_delayed_work(&priv->pga_work);
 
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
index 098c143..c6d1053 100644 (file)
@@ -125,7 +125,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8731->deemph;
+       ucontrol->value.integer.value[0] = wm8731->deemph;
 
        return 0;
 }
@@ -135,7 +135,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index 31bb480..9e71c76 100644 (file)
@@ -123,7 +123,7 @@ static struct {
 };
 
 static const unsigned int rates_11289[] = {
-       44100, 88235,
+       44100, 88200,
 };
 
 static const struct snd_pcm_hw_constraint_list constraints_11289 = {
@@ -150,7 +150,7 @@ static const struct snd_pcm_hw_constraint_list constraints_16384 = {
 };
 
 static const unsigned int rates_16934[] = {
-       44100, 88235,
+       44100, 88200,
 };
 
 static const struct snd_pcm_hw_constraint_list constraints_16934 = {
@@ -168,7 +168,7 @@ static const struct snd_pcm_hw_constraint_list constraints_18432 = {
 };
 
 static const unsigned int rates_22579[] = {
-       44100, 88235, 1764000
+       44100, 88200, 176400
 };
 
 static const struct snd_pcm_hw_constraint_list constraints_22579 = {
@@ -186,7 +186,7 @@ static const struct snd_pcm_hw_constraint_list constraints_24576 = {
 };
 
 static const unsigned int rates_36864[] = {
-       48000, 96000, 19200
+       48000, 96000, 192000
 };
 
 static const struct snd_pcm_hw_constraint_list constraints_36864 = {
index 21ca3a9..c50a595 100644 (file)
@@ -153,6 +153,7 @@ struct wm8753_priv {
        unsigned int hifi_fmt;
 
        int dai_func;
+       struct delayed_work charge_work;
 };
 
 #define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0)
@@ -1326,9 +1327,19 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
        return 0;
 }
 
+static void wm8753_charge_work(struct work_struct *work)
+{
+       struct wm8753_priv *wm8753 =
+               container_of(work, struct wm8753_priv, charge_work.work);
+
+       /* Set to 500k */
+       regmap_update_bits(wm8753->regmap, WM8753_PWR1, 0x0180, 0x0100);
+}
+
 static int wm8753_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        u16 pwr_reg = snd_soc_read(codec, WM8753_PWR1) & 0xfe3e;
 
        switch (level) {
@@ -1337,14 +1348,22 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
                break;
        case SND_SOC_BIAS_PREPARE:
-               /* set vmid to 5k for quick power up */
-               snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
+               /* Wait until fully charged */
+               flush_delayed_work(&wm8753->charge_work);
                break;
        case SND_SOC_BIAS_STANDBY:
-               /* mute dac and set vmid to 500k, enable VREF */
-               snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       /* set vmid to 5k for quick power up */
+                       snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
+                       schedule_delayed_work(&wm8753->charge_work,
+                               msecs_to_jiffies(caps_charge));
+               } else {
+                       /* mute dac and set vmid to 500k, enable VREF */
+                       snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
+               }
                break;
        case SND_SOC_BIAS_OFF:
+               cancel_delayed_work_sync(&wm8753->charge_work);
                snd_soc_write(codec, WM8753_PWR1, 0x0001);
                break;
        }
@@ -1428,38 +1447,12 @@ static struct snd_soc_dai_driver wm8753_dai[] = {
 },
 };
 
-static void wm8753_work(struct work_struct *work)
-{
-       struct snd_soc_dapm_context *dapm =
-               container_of(work, struct snd_soc_dapm_context,
-                            delayed_work.work);
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-       wm8753_set_bias_level(codec, dapm->bias_level);
-}
-
-static int wm8753_suspend(struct snd_soc_codec *codec)
-{
-       wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
 static int wm8753_resume(struct snd_soc_codec *codec)
 {
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 
        regcache_sync(wm8753->regmap);
 
-       wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* charge wm8753 caps */
-       if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
-               wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
-               codec->dapm.bias_level = SND_SOC_BIAS_ON;
-               queue_delayed_work(system_power_efficient_wq,
-                                  &codec->dapm.delayed_work,
-                                  msecs_to_jiffies(caps_charge));
-       }
-
        return 0;
 }
 
@@ -1468,7 +1461,7 @@ static int wm8753_probe(struct snd_soc_codec *codec)
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work);
+       INIT_DELAYED_WORK(&wm8753->charge_work, wm8753_charge_work);
 
        ret = wm8753_reset(codec);
        if (ret < 0) {
@@ -1476,14 +1469,8 @@ static int wm8753_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        wm8753->dai_func = 0;
 
-       /* charge output caps */
-       wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
-       schedule_delayed_work(&codec->dapm.delayed_work,
-                             msecs_to_jiffies(caps_charge));
-
        /* set the update bits */
        snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
        snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
@@ -1499,21 +1486,11 @@ static int wm8753_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-/* power down chip */
-static int wm8753_remove(struct snd_soc_codec *codec)
-{
-       flush_delayed_work(&codec->dapm.delayed_work);
-       wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
        .probe =        wm8753_probe,
-       .remove =       wm8753_remove,
-       .suspend =      wm8753_suspend,
        .resume =       wm8753_resume,
        .set_bias_level = wm8753_set_bias_level,
+       .suspend_bias_off = true,
 
        .controls = wm8753_snd_controls,
        .num_controls = ARRAY_SIZE(wm8753_snd_controls),
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c
new file mode 100644 (file)
index 0000000..5bd4af2
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * wm8804-i2c.c  --  WM8804 S/PDIF transceiver driver - I2C
+ *
+ * Copyright 2015 Cirrus Logic Inc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "wm8804.h"
+
+static int wm8804_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return wm8804_probe(&i2c->dev, regmap);
+}
+
+static int wm8804_i2c_remove(struct i2c_client *i2c)
+{
+       wm8804_remove(&i2c->dev);
+       return 0;
+}
+
+static const struct i2c_device_id wm8804_i2c_id[] = {
+       { "wm8804", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
+
+static const struct of_device_id wm8804_of_match[] = {
+       { .compatible = "wlf,wm8804", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8804_of_match);
+
+static struct i2c_driver wm8804_i2c_driver = {
+       .driver = {
+               .name = "wm8804",
+               .owner = THIS_MODULE,
+               .of_match_table = wm8804_of_match,
+       },
+       .probe = wm8804_i2c_probe,
+       .remove = wm8804_i2c_remove,
+       .id_table = wm8804_i2c_id
+};
+
+module_i2c_driver(wm8804_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver - I2C");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c
new file mode 100644 (file)
index 0000000..287e11e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * wm8804-spi.c  --  WM8804 S/PDIF transceiver driver - SPI
+ *
+ * Copyright 2015 Cirrus Logic Inc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "wm8804.h"
+
+static int wm8804_spi_probe(struct spi_device *spi)
+{
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return wm8804_probe(&spi->dev, regmap);
+}
+
+static int wm8804_spi_remove(struct spi_device *spi)
+{
+       wm8804_remove(&spi->dev);
+       return 0;
+}
+
+static const struct of_device_id wm8804_of_match[] = {
+       { .compatible = "wlf,wm8804", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8804_of_match);
+
+static struct spi_driver wm8804_spi_driver = {
+       .driver = {
+               .name = "wm8804",
+               .owner = THIS_MODULE,
+               .of_match_table = wm8804_of_match,
+       },
+       .probe = wm8804_spi_probe,
+       .remove = wm8804_spi_remove
+};
+
+module_spi_driver(wm8804_spi_driver);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver - SPI");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
index b2b0e68..1bd4ace 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/i2c.h>
 #include <linux/of_device.h>
-#include <linux/spi/spi.h>
-#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -185,9 +182,9 @@ static bool wm8804_volatile(struct device *dev, unsigned int reg)
        }
 }
 
-static int wm8804_reset(struct snd_soc_codec *codec)
+static int wm8804_reset(struct wm8804_priv *wm8804)
 {
-       return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0);
+       return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0);
 }
 
 static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -518,100 +515,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8804_remove(struct snd_soc_codec *codec)
-{
-       struct wm8804_priv *wm8804;
-       int i;
-
-       wm8804 = snd_soc_codec_get_drvdata(codec);
-
-       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
-               regulator_unregister_notifier(wm8804->supplies[i].consumer,
-                                             &wm8804->disable_nb[i]);
-       return 0;
-}
-
-static int wm8804_probe(struct snd_soc_codec *codec)
-{
-       struct wm8804_priv *wm8804;
-       int i, id1, id2, ret;
-
-       wm8804 = snd_soc_codec_get_drvdata(codec);
-
-       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
-               wm8804->supplies[i].supply = wm8804_supply_names[i];
-
-       ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
-                                wm8804->supplies);
-       if (ret) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               return ret;
-       }
-
-       wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
-       wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
-
-       /* This should really be moved into the regulator core */
-       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
-               ret = regulator_register_notifier(wm8804->supplies[i].consumer,
-                                                 &wm8804->disable_nb[i]);
-               if (ret != 0) {
-                       dev_err(codec->dev,
-                               "Failed to register regulator notifier: %d\n",
-                               ret);
-               }
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
-                                   wm8804->supplies);
-       if (ret) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               return ret;
-       }
-
-       id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
-       if (id1 < 0) {
-               dev_err(codec->dev, "Failed to read device ID: %d\n", id1);
-               ret = id1;
-               goto err_reg_enable;
-       }
-
-       id2 = snd_soc_read(codec, WM8804_DEVID2);
-       if (id2 < 0) {
-               dev_err(codec->dev, "Failed to read device ID: %d\n", id2);
-               ret = id2;
-               goto err_reg_enable;
-       }
-
-       id2 = (id2 << 8) | id1;
-
-       if (id2 != 0x8805) {
-               dev_err(codec->dev, "Invalid device ID: %#x\n", id2);
-               ret = -EINVAL;
-               goto err_reg_enable;
-       }
-
-       ret = snd_soc_read(codec, WM8804_DEVREV);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read device revision: %d\n",
-                       ret);
-               goto err_reg_enable;
-       }
-       dev_info(codec->dev, "revision %c\n", ret + 'A');
-
-       ret = wm8804_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
-               goto err_reg_enable;
-       }
-
-       return 0;
-
-err_reg_enable:
-       regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
-       return ret;
-}
-
 static const struct snd_soc_dai_ops wm8804_dai_ops = {
        .hw_params = wm8804_hw_params,
        .set_fmt = wm8804_set_fmt,
@@ -649,8 +552,6 @@ static struct snd_soc_dai_driver wm8804_dai = {
 };
 
 static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
-       .probe = wm8804_probe,
-       .remove = wm8804_remove,
        .set_bias_level = wm8804_set_bias_level,
        .idle_bias_off = true,
 
@@ -658,13 +559,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
        .num_controls = ARRAY_SIZE(wm8804_snd_controls),
 };
 
-static const struct of_device_id wm8804_of_match[] = {
-       { .compatible = "wlf,wm8804", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, wm8804_of_match);
-
-static const struct regmap_config wm8804_regmap_config = {
+const struct regmap_config wm8804_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 
@@ -675,128 +570,110 @@ static const struct regmap_config wm8804_regmap_config = {
        .reg_defaults = wm8804_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults),
 };
+EXPORT_SYMBOL_GPL(wm8804_regmap_config);
 
-#if defined(CONFIG_SPI_MASTER)
-static int wm8804_spi_probe(struct spi_device *spi)
+int wm8804_probe(struct device *dev, struct regmap *regmap)
 {
        struct wm8804_priv *wm8804;
-       int ret;
+       unsigned int id1, id2;
+       int i, ret;
 
-       wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL);
+       wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL);
        if (!wm8804)
                return -ENOMEM;
 
-       wm8804->regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config);
-       if (IS_ERR(wm8804->regmap)) {
-               ret = PTR_ERR(wm8804->regmap);
+       dev_set_drvdata(dev, wm8804);
+
+       wm8804->regmap = regmap;
+
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
+               wm8804->supplies[i].supply = wm8804_supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8804->supplies),
+                                     wm8804->supplies);
+       if (ret) {
+               dev_err(dev, "Failed to request supplies: %d\n", ret);
                return ret;
        }
 
-       spi_set_drvdata(spi, wm8804);
+       wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
+       wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
 
-       ret = snd_soc_register_codec(&spi->dev,
-                                    &soc_codec_dev_wm8804, &wm8804_dai, 1);
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
+               ret = regulator_register_notifier(wm8804->supplies[i].consumer,
+                                                 &wm8804->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
 
-       return ret;
-}
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+                                   wm8804->supplies);
+       if (ret) {
+               dev_err(dev, "Failed to enable supplies: %d\n", ret);
+               goto err_reg_enable;
+       }
 
-static int wm8804_spi_remove(struct spi_device *spi)
-{
-       snd_soc_unregister_codec(&spi->dev);
-       return 0;
-}
+       ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read device ID: %d\n", ret);
+               goto err_reg_enable;
+       }
 
-static struct spi_driver wm8804_spi_driver = {
-       .driver = {
-               .name = "wm8804",
-               .owner = THIS_MODULE,
-               .of_match_table = wm8804_of_match,
-       },
-       .probe = wm8804_spi_probe,
-       .remove = wm8804_spi_remove
-};
-#endif
+       ret = regmap_read(regmap, WM8804_DEVID2, &id2);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read device ID: %d\n", ret);
+               goto err_reg_enable;
+       }
 
-#if IS_ENABLED(CONFIG_I2C)
-static int wm8804_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
-{
-       struct wm8804_priv *wm8804;
-       int ret;
+       id2 = (id2 << 8) | id1;
 
-       wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL);
-       if (!wm8804)
-               return -ENOMEM;
+       if (id2 != 0x8805) {
+               dev_err(dev, "Invalid device ID: %#x\n", id2);
+               ret = -EINVAL;
+               goto err_reg_enable;
+       }
 
-       wm8804->regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config);
-       if (IS_ERR(wm8804->regmap)) {
-               ret = PTR_ERR(wm8804->regmap);
-               return ret;
+       ret = regmap_read(regmap, WM8804_DEVREV, &id1);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_reg_enable;
        }
+       dev_info(dev, "revision %c\n", id1 + 'A');
 
-       i2c_set_clientdata(i2c, wm8804);
+       ret = wm8804_reset(wm8804);
+       if (ret < 0) {
+               dev_err(dev, "Failed to issue reset: %d\n", ret);
+               goto err_reg_enable;
+       }
 
-       ret = snd_soc_register_codec(&i2c->dev,
-                                    &soc_codec_dev_wm8804, &wm8804_dai, 1);
+       return snd_soc_register_codec(dev, &soc_codec_dev_wm8804,
+                                     &wm8804_dai, 1);
+
+err_reg_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wm8804_probe);
 
-static int wm8804_i2c_remove(struct i2c_client *i2c)
+void wm8804_remove(struct device *dev)
 {
-       snd_soc_unregister_codec(&i2c->dev);
-       return 0;
-}
-
-static const struct i2c_device_id wm8804_i2c_id[] = {
-       { "wm8804", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
-
-static struct i2c_driver wm8804_i2c_driver = {
-       .driver = {
-               .name = "wm8804",
-               .owner = THIS_MODULE,
-               .of_match_table = wm8804_of_match,
-       },
-       .probe = wm8804_i2c_probe,
-       .remove = wm8804_i2c_remove,
-       .id_table = wm8804_i2c_id
-};
-#endif
+       struct wm8804_priv *wm8804;
+       int i;
 
-static int __init wm8804_modinit(void)
-{
-       int ret = 0;
+       wm8804 = dev_get_drvdata(dev);
 
-#if IS_ENABLED(CONFIG_I2C)
-       ret = i2c_add_driver(&wm8804_i2c_driver);
-       if (ret) {
-               printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
-                      ret);
-       }
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       ret = spi_register_driver(&wm8804_spi_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n",
-                      ret);
-       }
-#endif
-       return ret;
-}
-module_init(wm8804_modinit);
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
+               regulator_unregister_notifier(wm8804->supplies[i].consumer,
+                                             &wm8804->disable_nb[i]);
 
-static void __exit wm8804_exit(void)
-{
-#if IS_ENABLED(CONFIG_I2C)
-       i2c_del_driver(&wm8804_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       spi_unregister_driver(&wm8804_spi_driver);
-#endif
+       snd_soc_unregister_codec(dev);
 }
-module_exit(wm8804_exit);
+EXPORT_SYMBOL_GPL(wm8804_remove);
 
 MODULE_DESCRIPTION("ASoC WM8804 driver");
 MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
index e72d4f4..a39a256 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _WM8804_H
 #define _WM8804_H
 
+#include <linux/regmap.h>
+
 /*
  * Register values.
  */
@@ -62,4 +64,9 @@
 #define WM8804_MCLKDIV_256FS                   0
 #define WM8804_MCLKDIV_128FS                   1
 
+extern const struct regmap_config wm8804_regmap_config;
+
+int wm8804_probe(struct device *dev, struct regmap *regmap);
+void wm8804_remove(struct device *dev);
+
 #endif  /* _WM8804_H */
index dde462c..04b04f8 100644 (file)
@@ -442,7 +442,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8903->deemph;
+       ucontrol->value.integer.value[0] = wm8903->deemph;
 
        return 0;
 }
@@ -452,7 +452,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index d3b3f57..215e93c 100644 (file)
@@ -525,7 +525,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8904->deemph;
+       ucontrol->value.integer.value[0] = wm8904->deemph;
        return 0;
 }
 
@@ -534,7 +534,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 1ab2d46..00bec91 100644 (file)
@@ -393,7 +393,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8955->deemph;
+       ucontrol->value.integer.value[0] = wm8955->deemph;
        return 0;
 }
 
@@ -402,7 +402,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index cf8fecf..3035d98 100644 (file)
@@ -184,7 +184,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8960->deemph;
+       ucontrol->value.integer.value[0] = wm8960->deemph;
        return 0;
 }
 
@@ -193,7 +193,7 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 39ddb9b..f9cbabd 100644 (file)
 
 #define        WM8971_REG_COUNT                43
 
-static struct workqueue_struct *wm8971_workq = NULL;
-
 /* codec private data */
 struct wm8971_priv {
        unsigned int sysclk;
+       struct delayed_work charge_work;
+       struct regmap *regmap;
 };
 
 /*
@@ -552,9 +552,19 @@ static int wm8971_mute(struct snd_soc_dai *dai, int mute)
        return 0;
 }
 
+static void wm8971_charge_work(struct work_struct *work)
+{
+       struct wm8971_priv *wm8971 =
+               container_of(work, struct wm8971_priv, charge_work.work);
+
+       /* Set to 500k */
+       regmap_update_bits(wm8971->regmap, WM8971_PWR1, 0x0180, 0x0100);
+}
+
 static int wm8971_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
+       struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
        u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
 
        switch (level) {
@@ -563,15 +573,24 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
                break;
        case SND_SOC_BIAS_PREPARE:
+               /* Wait until fully charged */
+               flush_delayed_work(&wm8971->charge_work);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        snd_soc_cache_sync(codec);
+                       /* charge output caps - set vmid to 5k for quick power up */
+                       snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x01c0);
+                       queue_delayed_work(system_power_efficient_wq,
+                               &wm8971->charge_work, msecs_to_jiffies(1000));
+               } else {
+                       /* mute dac and set vmid to 500k, enable VREF */
+                       snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
+               }
 
-               /* mute dac and set vmid to 500k, enable VREF */
-               snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
                break;
        case SND_SOC_BIAS_OFF:
+               cancel_delayed_work_sync(&wm8971->charge_work);
                snd_soc_write(codec, WM8971_PWR1, 0x0001);
                break;
        }
@@ -610,58 +629,14 @@ static struct snd_soc_dai_driver wm8971_dai = {
        .ops = &wm8971_dai_ops,
 };
 
-static void wm8971_work(struct work_struct *work)
-{
-       struct snd_soc_dapm_context *dapm =
-               container_of(work, struct snd_soc_dapm_context,
-                            delayed_work.work);
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-       wm8971_set_bias_level(codec, codec->dapm.bias_level);
-}
-
-static int wm8971_suspend(struct snd_soc_codec *codec)
-{
-       wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
-static int wm8971_resume(struct snd_soc_codec *codec)
-{
-       u16 reg;
-
-       wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* charge wm8971 caps */
-       if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
-               reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
-               snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
-               codec->dapm.bias_level = SND_SOC_BIAS_ON;
-               queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work,
-                       msecs_to_jiffies(1000));
-       }
-
-       return 0;
-}
-
 static int wm8971_probe(struct snd_soc_codec *codec)
 {
-       int ret = 0;
-       u16 reg;
+       struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
 
-       INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work);
-       wm8971_workq = create_workqueue("wm8971");
-       if (wm8971_workq == NULL)
-               return -ENOMEM;
+       INIT_DELAYED_WORK(&wm8971->charge_work, wm8971_charge_work);
 
        wm8971_reset(codec);
 
-       /* charge output caps - set vmid to 5k for quick power up */
-       reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
-       snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
-       codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
-       queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work,
-               msecs_to_jiffies(1000));
-
        /* set the update bits */
        snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100);
        snd_soc_update_bits(codec, WM8971_RDAC, 0x0100, 0x0100);
@@ -672,26 +647,13 @@ static int wm8971_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100);
        snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100);
 
-       return ret;
-}
-
-
-/* power down chip */
-static int wm8971_remove(struct snd_soc_codec *codec)
-{
-       wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       if (wm8971_workq)
-               destroy_workqueue(wm8971_workq);
        return 0;
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
        .probe =        wm8971_probe,
-       .remove =       wm8971_remove,
-       .suspend =      wm8971_suspend,
-       .resume =       wm8971_resume,
        .set_bias_level = wm8971_set_bias_level,
+       .suspend_bias_off = true,
 
        .controls = wm8971_snd_controls,
        .num_controls = ARRAY_SIZE(wm8971_snd_controls),
@@ -715,7 +677,6 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm8971_priv *wm8971;
-       struct regmap *regmap;
        int ret;
 
        wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv),
@@ -723,9 +684,9 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
        if (wm8971 == NULL)
                return -ENOMEM;
 
-       regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap);
-       if (IS_ERR(regmap))
-               return PTR_ERR(regmap);
+       wm8971->regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap);
+       if (IS_ERR(wm8971->regmap))
+               return PTR_ERR(wm8971->regmap);
 
        i2c_set_clientdata(i2c, wm8971);
 
index 9517571..98c9525 100644 (file)
@@ -180,7 +180,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val = ucontrol->value.enumerated.item[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
@@ -193,7 +193,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&wm9712->lock);
        old = wm9712->hp_mixer[mixer];
-       if (ucontrol->value.enumerated.item[0])
+       if (ucontrol->value.integer.value[0])
                wm9712->hp_mixer[mixer] |= mask;
        else
                wm9712->hp_mixer[mixer] &= ~mask;
@@ -231,7 +231,7 @@ static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
        mixer = mc->shift >> 8;
        shift = mc->shift & 0xff;
 
-       ucontrol->value.enumerated.item[0] =
+       ucontrol->value.integer.value[0] =
                (wm9712->hp_mixer[mixer] >> shift) & 1;
 
        return 0;
index 6822291..7955295 100644 (file)
@@ -255,7 +255,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val = ucontrol->value.enumerated.item[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
@@ -268,7 +268,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&wm9713->lock);
        old = wm9713->hp_mixer[mixer];
-       if (ucontrol->value.enumerated.item[0])
+       if (ucontrol->value.integer.value[0])
                wm9713->hp_mixer[mixer] |= mask;
        else
                wm9713->hp_mixer[mixer] &= ~mask;
@@ -306,7 +306,7 @@ static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
        mixer = mc->shift >> 8;
        shift = mc->shift & 0xff;
 
-       ucontrol->value.enumerated.item[0] =
+       ucontrol->value.integer.value[0] =
                (wm9713->hp_mixer[mixer] >> shift) & 1;
 
        return 0;
index ff67b33..d01c209 100644 (file)
@@ -420,10 +420,9 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
 
        memcpy(ctl->cache, p, ctl->len);
 
-       if (!ctl->enabled) {
-               ctl->set = 1;
+       ctl->set = 1;
+       if (!ctl->enabled)
                return 0;
-       }
 
        return wm_coeff_write_control(kcontrol, p, ctl->len);
 }
@@ -1185,7 +1184,6 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
        int ret, pos, blocks, type, offset, reg;
        char *file;
        struct wm_adsp_buf *buf;
-       int tmp;
 
        file = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (file == NULL)
@@ -1335,12 +1333,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                        }
                }
 
-               tmp = le32_to_cpu(blk->len) % 4;
-               if (tmp)
-                       pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk);
-               else
-                       pos += le32_to_cpu(blk->len) + sizeof(*blk);
-
+               pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
                blocks++;
        }
 
index 2b81ca4..3736d9a 100644 (file)
@@ -1,14 +1,16 @@
 config SND_DAVINCI_SOC
-       tristate "SoC Audio for TI DAVINCI"
+       tristate
        depends on ARCH_DAVINCI
+       select SND_EDMA_SOC
 
 config SND_EDMA_SOC
-       tristate "SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)"
-       depends on SOC_AM33XX || SOC_AM43XX
+       tristate "SoC Audio for Texas Instruments chips using eDMA"
+       depends on SOC_AM33XX || SOC_AM43XX || ARCH_DAVINCI
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M here if you want audio support for TI SoC which uses eDMA.
          The following line of SoCs are supported by this platform driver:
+         - daVinci devices
          - AM335x
          - AM437x/AM438x
 
@@ -17,7 +19,7 @@ config SND_DAVINCI_SOC_I2S
 
 config SND_DAVINCI_SOC_MCASP
        tristate "Multichannel Audio Serial Port (McASP) support"
-       depends on SND_DAVINCI_SOC || SND_OMAP_SOC || SND_EDMA_SOC
+       depends on SND_OMAP_SOC || SND_EDMA_SOC
        help
          Say Y or M here if you want to have support for McASP IP found in
          various Texas Instruments SoCs like:
@@ -45,7 +47,7 @@ config SND_AM33XX_SOC_EVM
 
 config SND_DAVINCI_SOC_EVM
        tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
-       depends on SND_DAVINCI_SOC && I2C
+       depends on SND_EDMA_SOC && I2C
        depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
        select SND_DAVINCI_SOC_GENERIC_EVM
        help
@@ -73,7 +75,7 @@ endchoice
 
 config  SND_DM6467_SOC_EVM
        tristate "SoC Audio support for DaVinci DM6467 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C
+       depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
        select SND_SOC_SPDIF
 
@@ -82,7 +84,7 @@ config  SND_DM6467_SOC_EVM
 
 config  SND_DA830_SOC_EVM
        tristate "SoC Audio support for DA830/OMAP-L137 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C
+       depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
 
        help
@@ -91,7 +93,7 @@ config  SND_DA830_SOC_EVM
 
 config  SND_DA850_SOC_EVM
        tristate "SoC Audio support for DA850/OMAP-L138 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C
+       depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
        help
          Say Y if you want to add support for SoC audio on TI
index 09bf2ba..f883933 100644 (file)
@@ -1,11 +1,9 @@
 # DAVINCI Platform Support
-snd-soc-davinci-objs := davinci-pcm.o
 snd-soc-edma-objs := edma-pcm.o
 snd-soc-davinci-i2s-objs := davinci-i2s.o
 snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
 snd-soc-davinci-vcif-objs:= davinci-vcif.o
 
-obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
 obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
 obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
 obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
index b6bb594..8c2b9be 100644 (file)
@@ -425,18 +425,8 @@ static int davinci_evm_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int davinci_evm_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-
-       return 0;
-}
-
 static struct platform_driver davinci_evm_driver = {
        .probe          = davinci_evm_probe,
-       .remove         = davinci_evm_remove,
        .driver         = {
                .name   = "davinci_evm",
                .pm     = &snd_soc_pm_ops,
index 15fb28f..56cb4d9 100644 (file)
@@ -23,8 +23,9 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
-#include "davinci-pcm.h"
+#include "edma-pcm.h"
 #include "davinci-i2s.h"
 
 
@@ -122,7 +123,8 @@ static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
 
 struct davinci_mcbsp_dev {
        struct device *dev;
-       struct davinci_pcm_dma_params   dma_params[2];
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       int dma_request[2];
        void __iomem                    *base;
 #define MOD_DSP_A      0
 #define MOD_DSP_B      1
@@ -419,8 +421,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-       struct davinci_pcm_dma_params *dma_params =
-                                       &dev->dma_params[substream->stream];
        struct snd_interval *i = NULL;
        int mcbsp_word_length, master;
        unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
@@ -532,8 +532,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                        return -EINVAL;
                }
        }
-       dma_params->acnt = dma_params->data_type = data_type[fmt];
-       dma_params->fifo_level = 0;
        mcbsp_word_length = asp_word_length[fmt];
 
        switch (master) {
@@ -600,15 +598,6 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
-static int davinci_i2s_startup(struct snd_pcm_substream *substream,
-                              struct snd_soc_dai *dai)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
-       return 0;
-}
-
 static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
@@ -620,7 +609,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
 #define DAVINCI_I2S_RATES      SNDRV_PCM_RATE_8000_96000
 
 static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
-       .startup        = davinci_i2s_startup,
        .shutdown       = davinci_i2s_shutdown,
        .prepare        = davinci_i2s_prepare,
        .trigger        = davinci_i2s_trigger,
@@ -630,7 +618,18 @@ static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
 
 };
 
+static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+       return 0;
+}
+
 static struct snd_soc_dai_driver davinci_i2s_dai = {
+       .probe = davinci_i2s_dai_probe,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -651,11 +650,9 @@ static const struct snd_soc_component_driver davinci_i2s_component = {
 
 static int davinci_i2s_probe(struct platform_device *pdev)
 {
-       struct snd_platform_data *pdata = pdev->dev.platform_data;
        struct davinci_mcbsp_dev *dev;
        struct resource *mem, *ioarea, *res;
-       enum dma_event_q asp_chan_q = EVENTQ_0;
-       enum dma_event_q ram_chan_q = EVENTQ_1;
+       int *dma;
        int ret;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -676,22 +673,6 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                           GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
-       if (pdata) {
-               dev->enable_channel_combine = pdata->enable_channel_combine;
-               dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size =
-                       pdata->sram_size_playback;
-               dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
-                       pdata->sram_size_capture;
-               dev->clk_input_pin = pdata->clk_input_pin;
-               dev->i2s_accurate_sck = pdata->i2s_accurate_sck;
-               asp_chan_q = pdata->asp_chan_q;
-               ram_chan_q = pdata->ram_chan_q;
-       }
-
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].asp_chan_q   = asp_chan_q;
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].ram_chan_q   = ram_chan_q;
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].asp_chan_q    = asp_chan_q;
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q    = ram_chan_q;
 
        dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk))
@@ -705,10 +686,10 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                goto err_release_clk;
        }
 
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
+       dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
            (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
 
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
+       dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
            (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG);
 
        /* first TX, then RX */
@@ -718,7 +699,9 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                ret = -ENXIO;
                goto err_release_clk;
        }
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start;
+       dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
+       *dma = res->start;
+       dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = dma;
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!res) {
@@ -726,9 +709,11 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                ret = -ENXIO;
                goto err_release_clk;
        }
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
-       dev->dev = &pdev->dev;
+       dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE];
+       *dma = res->start;
+       dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = dma;
 
+       dev->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, dev);
 
        ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
@@ -736,7 +721,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        if (ret != 0)
                goto err_release_clk;
 
-       ret = davinci_soc_platform_register(&pdev->dev);
+       ret = edma_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
                goto err_unregister_component;
index de3b155..0c88299 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
+#include <linux/platform_data/davinci_asp.h>
 
 #include <sound/asoundef.h>
 #include <sound/core.h>
@@ -36,7 +37,6 @@
 #include <sound/dmaengine_pcm.h>
 #include <sound/omap-pcm.h>
 
-#include "davinci-pcm.h"
 #include "edma-pcm.h"
 #include "davinci-mcasp.h"
 
@@ -65,7 +65,6 @@ struct davinci_mcasp_context {
 };
 
 struct davinci_mcasp {
-       struct davinci_pcm_dma_params dma_params[2];
        struct snd_dmaengine_dai_dma_data dma_data[2];
        void __iomem *base;
        u32 fifo_base;
@@ -82,6 +81,7 @@ struct davinci_mcasp {
        u16     bclk_lrclk_ratio;
        int     streams;
        u32     irq_request[2];
+       int     dma_request[2];
 
        int     sysclk_freq;
        bool    bclk_master;
@@ -441,6 +441,18 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
                mcasp->bclk_master = 1;
                break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               /* codec is clock slave and frame master */
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+               mcasp->bclk_master = 1;
+               break;
        case SND_SOC_DAIFMT_CBM_CFS:
                /* codec is clock master and frame slave */
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
@@ -631,7 +643,6 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
 static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
                                 int period_words, int channels)
 {
-       struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream];
        struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
        int i;
        u8 tx_ser = 0;
@@ -699,10 +710,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
                         * For example if three serializers are enabled the DMA
                         * need to transfer three words per DMA request.
                         */
-                       dma_params->fifo_level = active_serializers;
                        dma_data->maxburst = active_serializers;
                } else {
-                       dma_params->fifo_level = 0;
                        dma_data->maxburst = 0;
                }
                return 0;
@@ -734,7 +743,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
        /* Configure the burst size for platform drivers */
        if (numevt == 1)
                numevt = 0;
-       dma_params->fifo_level = numevt;
        dma_data->maxburst = numevt;
 
        return 0;
@@ -860,8 +868,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_soc_dai *cpu_dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct davinci_pcm_dma_params *dma_params =
-                                       &mcasp->dma_params[substream->stream];
        int word_length;
        int channels = params_channels(params);
        int period_size = params_period_size(params);
@@ -902,31 +908,26 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_U8:
        case SNDRV_PCM_FORMAT_S8:
-               dma_params->data_type = 1;
                word_length = 8;
                break;
 
        case SNDRV_PCM_FORMAT_U16_LE:
        case SNDRV_PCM_FORMAT_S16_LE:
-               dma_params->data_type = 2;
                word_length = 16;
                break;
 
        case SNDRV_PCM_FORMAT_U24_3LE:
        case SNDRV_PCM_FORMAT_S24_3LE:
-               dma_params->data_type = 3;
                word_length = 24;
                break;
 
        case SNDRV_PCM_FORMAT_U24_LE:
        case SNDRV_PCM_FORMAT_S24_LE:
-               dma_params->data_type = 4;
                word_length = 24;
                break;
 
        case SNDRV_PCM_FORMAT_U32_LE:
        case SNDRV_PCM_FORMAT_S32_LE:
-               dma_params->data_type = 4;
                word_length = 32;
                break;
 
@@ -935,11 +936,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level)
-               dma_params->acnt = 4;
-       else
-               dma_params->acnt = dma_params->data_type;
-
        davinci_config_channel_size(mcasp, word_length);
 
        if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
@@ -1043,17 +1039,8 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
-       if (mcasp->version >= MCASP_VERSION_3) {
-               /* Using dmaengine PCM */
-               dai->playback_dma_data =
-                               &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-               dai->capture_dma_data =
-                               &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-       } else {
-               /* Using davinci-pcm */
-               dai->playback_dma_data = mcasp->dma_params;
-               dai->capture_dma_data = mcasp->dma_params;
-       }
+       dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
 
        return 0;
 }
@@ -1172,28 +1159,24 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
 static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
        .tx_dma_offset = 0x400,
        .rx_dma_offset = 0x400,
-       .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_1,
 };
 
 static struct davinci_mcasp_pdata da830_mcasp_pdata = {
        .tx_dma_offset = 0x2000,
        .rx_dma_offset = 0x2000,
-       .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_2,
 };
 
 static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
        .tx_dma_offset = 0,
        .rx_dma_offset = 0,
-       .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_3,
 };
 
 static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
        .tx_dma_offset = 0x200,
        .rx_dma_offset = 0x284,
-       .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_4,
 };
 
@@ -1370,12 +1353,12 @@ nodata:
 
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
-       struct davinci_pcm_dma_params *dma_params;
        struct snd_dmaengine_dai_dma_data *dma_data;
        struct resource *mem, *ioarea, *res, *dat;
        struct davinci_mcasp_pdata *pdata;
        struct davinci_mcasp *mcasp;
        char *irq_name;
+       int *dma;
        int irq;
        int ret;
 
@@ -1509,59 +1492,45 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (dat)
                mcasp->dat_port = true;
 
-       dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
        dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-       dma_params->asp_chan_q = pdata->asp_chan_q;
-       dma_params->ram_chan_q = pdata->ram_chan_q;
-       dma_params->sram_pool = pdata->sram_pool;
-       dma_params->sram_size = pdata->sram_size_playback;
        if (dat)
-               dma_params->dma_addr = dat->start;
+               dma_data->addr = dat->start;
        else
-               dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
-
-       /* Unconditional dmaengine stuff */
-       dma_data->addr = dma_params->dma_addr;
+               dma_data->addr = mem->start + pdata->tx_dma_offset;
 
+       dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (res)
-               dma_params->channel = res->start;
+               *dma = res->start;
        else
-               dma_params->channel = pdata->tx_dma_channel;
+               *dma = pdata->tx_dma_channel;
 
        /* dmaengine filter data for DT and non-DT boot */
        if (pdev->dev.of_node)
                dma_data->filter_data = "tx";
        else
-               dma_data->filter_data = &dma_params->channel;
+               dma_data->filter_data = dma;
 
        /* RX is not valid in DIT mode */
        if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
-               dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
                dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-               dma_params->asp_chan_q = pdata->asp_chan_q;
-               dma_params->ram_chan_q = pdata->ram_chan_q;
-               dma_params->sram_pool = pdata->sram_pool;
-               dma_params->sram_size = pdata->sram_size_capture;
                if (dat)
-                       dma_params->dma_addr = dat->start;
+                       dma_data->addr = dat->start;
                else
-                       dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
-
-               /* Unconditional dmaengine stuff */
-               dma_data->addr = dma_params->dma_addr;
+                       dma_data->addr = mem->start + pdata->rx_dma_offset;
 
+               dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
                res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
                if (res)
-                       dma_params->channel = res->start;
+                       *dma = res->start;
                else
-                       dma_params->channel = pdata->rx_dma_channel;
+                       *dma = pdata->rx_dma_channel;
 
                /* dmaengine filter data for DT and non-DT boot */
                if (pdev->dev.of_node)
                        dma_data->filter_data = "rx";
                else
-                       dma_data->filter_data = &dma_params->channel;
+                       dma_data->filter_data = dma;
        }
 
        if (mcasp->version < MCASP_VERSION_3) {
@@ -1584,17 +1553,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                goto err;
 
        switch (mcasp->version) {
-#if IS_BUILTIN(CONFIG_SND_DAVINCI_SOC) || \
-       (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
-        IS_MODULE(CONFIG_SND_DAVINCI_SOC))
-       case MCASP_VERSION_1:
-       case MCASP_VERSION_2:
-               ret = davinci_soc_platform_register(&pdev->dev);
-               break;
-#endif
 #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
        (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
         IS_MODULE(CONFIG_SND_EDMA_SOC))
+       case MCASP_VERSION_1:
+       case MCASP_VERSION_2:
        case MCASP_VERSION_3:
                ret = edma_pcm_platform_register(&pdev->dev);
                break;
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
deleted file mode 100644 (file)
index 7809e9d..0000000
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- * ALSA PCM interface for the TI DAVINCI processor
- *
- * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- * added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/genalloc.h>
-#include <linux/platform_data/edma.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-
-#include "davinci-pcm.h"
-
-#ifdef DEBUG
-static void print_buf_info(int slot, char *name)
-{
-       struct edmacc_param p;
-       if (slot < 0)
-               return;
-       edma_read_slot(slot, &p);
-       printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n",
-                       name, slot, p.opt, p.src, p.a_b_cnt, p.dst);
-       printk(KERN_DEBUG "    src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n",
-                       p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt);
-}
-#else
-static void print_buf_info(int slot, char *name)
-{
-}
-#endif
-
-static struct snd_pcm_hardware pcm_hardware_playback = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME|
-                SNDRV_PCM_INFO_BATCH),
-       .buffer_bytes_max = 128 * 1024,
-       .period_bytes_min = 32,
-       .period_bytes_max = 8 * 1024,
-       .periods_min = 16,
-       .periods_max = 255,
-       .fifo_size = 0,
-};
-
-static struct snd_pcm_hardware pcm_hardware_capture = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE |
-                SNDRV_PCM_INFO_BATCH),
-       .buffer_bytes_max = 128 * 1024,
-       .period_bytes_min = 32,
-       .period_bytes_max = 8 * 1024,
-       .periods_min = 16,
-       .periods_max = 255,
-       .fifo_size = 0,
-};
-
-/*
- * How ping/pong works....
- *
- * Playback:
- * ram_params - copys 2*ping_size from start of SDRAM to iram,
- *     links to ram_link2
- * ram_link2 - copys rest of SDRAM to iram in ping_size units,
- *     links to ram_link
- * ram_link - copys entire SDRAM to iram in ping_size uints,
- *     links to self
- *
- * asp_params - same as asp_link[0]
- * asp_link[0] - copys from lower half of iram to asp port
- *     links to asp_link[1], triggers iram copy event on completion
- * asp_link[1] - copys from upper half of iram to asp port
- *     links to asp_link[0], triggers iram copy event on completion
- *     triggers interrupt only needed to let upper SOC levels update position
- *     in stream on completion
- *
- * When playback is started:
- *     ram_params started
- *     asp_params started
- *
- * Capture:
- * ram_params - same as ram_link,
- *     links to ram_link
- * ram_link - same as playback
- *     links to self
- *
- * asp_params - same as playback
- * asp_link[0] - same as playback
- * asp_link[1] - same as playback
- *
- * When capture is started:
- *     asp_params started
- */
-struct davinci_runtime_data {
-       spinlock_t lock;
-       int period;             /* current DMA period */
-       int asp_channel;        /* Master DMA channel */
-       int asp_link[2];        /* asp parameter link channel, ping/pong */
-       struct davinci_pcm_dma_params *params;  /* DMA params */
-       int ram_channel;
-       int ram_link;
-       int ram_link2;
-       struct edmacc_param asp_params;
-       struct edmacc_param ram_params;
-};
-
-static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       prtd->period++;
-       if (unlikely(prtd->period >= runtime->periods))
-               prtd->period = 0;
-}
-
-static void davinci_pcm_period_reset(struct snd_pcm_substream *substream)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-
-       prtd->period = 0;
-}
-/*
- * Not used with ping/pong
- */
-static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int period_size;
-       unsigned int dma_offset;
-       dma_addr_t dma_pos;
-       dma_addr_t src, dst;
-       unsigned short src_bidx, dst_bidx;
-       unsigned short src_cidx, dst_cidx;
-       unsigned int data_type;
-       unsigned short acnt;
-       unsigned int count;
-       unsigned int fifo_level;
-
-       period_size = snd_pcm_lib_period_bytes(substream);
-       dma_offset = prtd->period * period_size;
-       dma_pos = runtime->dma_addr + dma_offset;
-       fifo_level = prtd->params->fifo_level;
-
-       pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
-               "dma_ptr = %x period_size=%x\n", prtd->asp_link[0], dma_pos,
-               period_size);
-
-       data_type = prtd->params->data_type;
-       count = period_size / data_type;
-       if (fifo_level)
-               count /= fifo_level;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               src = dma_pos;
-               dst = prtd->params->dma_addr;
-               src_bidx = data_type;
-               dst_bidx = 4;
-               src_cidx = data_type * fifo_level;
-               dst_cidx = 0;
-       } else {
-               src = prtd->params->dma_addr;
-               dst = dma_pos;
-               src_bidx = 0;
-               dst_bidx = data_type;
-               src_cidx = 0;
-               dst_cidx = data_type * fifo_level;
-       }
-
-       acnt = prtd->params->acnt;
-       edma_set_src(prtd->asp_link[0], src, INCR, W8BIT);
-       edma_set_dest(prtd->asp_link[0], dst, INCR, W8BIT);
-
-       edma_set_src_index(prtd->asp_link[0], src_bidx, src_cidx);
-       edma_set_dest_index(prtd->asp_link[0], dst_bidx, dst_cidx);
-
-       if (!fifo_level)
-               edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0,
-                                                       ASYNC);
-       else
-               edma_set_transfer_params(prtd->asp_link[0], acnt,
-                                               fifo_level,
-                                               count, fifo_level,
-                                               ABSYNC);
-}
-
-static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
-{
-       struct snd_pcm_substream *substream = data;
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-
-       print_buf_info(prtd->ram_channel, "i ram_channel");
-       pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status);
-
-       if (unlikely(ch_status != EDMA_DMA_COMPLETE))
-               return;
-
-       if (snd_pcm_running(substream)) {
-               spin_lock(&prtd->lock);
-               if (prtd->ram_channel < 0) {
-                       /* No ping/pong must fix up link dma data*/
-                       davinci_pcm_enqueue_dma(substream);
-               }
-               davinci_pcm_period_elapsed(substream);
-               spin_unlock(&prtd->lock);
-               snd_pcm_period_elapsed(substream);
-       }
-}
-
-#ifdef CONFIG_GENERIC_ALLOCATOR
-static int allocate_sram(struct snd_pcm_substream *substream,
-               struct gen_pool *sram_pool, unsigned size,
-               struct snd_pcm_hardware *ppcm)
-{
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       struct snd_dma_buffer *iram_dma = NULL;
-       dma_addr_t iram_phys = 0;
-       void *iram_virt = NULL;
-
-       if (buf->private_data || !size)
-               return 0;
-
-       ppcm->period_bytes_max = size;
-       iram_virt = gen_pool_dma_alloc(sram_pool, size, &iram_phys);
-       if (!iram_virt)
-               goto exit1;
-       iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL);
-       if (!iram_dma)
-               goto exit2;
-       iram_dma->area = iram_virt;
-       iram_dma->addr = iram_phys;
-       memset(iram_dma->area, 0, size);
-       iram_dma->bytes = size;
-       buf->private_data = iram_dma;
-       return 0;
-exit2:
-       if (iram_virt)
-               gen_pool_free(sram_pool, (unsigned)iram_virt, size);
-exit1:
-       return -ENOMEM;
-}
-
-static void davinci_free_sram(struct snd_pcm_substream *substream,
-                             struct snd_dma_buffer *iram_dma)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct gen_pool *sram_pool = prtd->params->sram_pool;
-
-       gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes);
-}
-#else
-static int allocate_sram(struct snd_pcm_substream *substream,
-               struct gen_pool *sram_pool, unsigned size,
-               struct snd_pcm_hardware *ppcm)
-{
-       return 0;
-}
-
-static void davinci_free_sram(struct snd_pcm_substream *substream,
-                             struct snd_dma_buffer *iram_dma)
-{
-}
-#endif
-
-/*
- * Only used with ping/pong.
- * This is called after runtime->dma_addr, period_bytes and data_type are valid
- */
-static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
-{
-       unsigned short ram_src_cidx, ram_dst_cidx;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct davinci_runtime_data *prtd = runtime->private_data;
-       struct snd_dma_buffer *iram_dma =
-               (struct snd_dma_buffer *)substream->dma_buffer.private_data;
-       struct davinci_pcm_dma_params *params = prtd->params;
-       unsigned int data_type = params->data_type;
-       unsigned int acnt = params->acnt;
-       /* divide by 2 for ping/pong */
-       unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1;
-       unsigned int fifo_level = prtd->params->fifo_level;
-       unsigned int count;
-       if ((data_type == 0) || (data_type > 4)) {
-               printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type);
-               return -EINVAL;
-       }
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dma_addr_t asp_src_pong = iram_dma->addr + ping_size;
-               ram_src_cidx = ping_size;
-               ram_dst_cidx = -ping_size;
-               edma_set_src(prtd->asp_link[1], asp_src_pong, INCR, W8BIT);
-
-               edma_set_src_index(prtd->asp_link[0], data_type,
-                               data_type * fifo_level);
-               edma_set_src_index(prtd->asp_link[1], data_type,
-                               data_type * fifo_level);
-
-               edma_set_src(prtd->ram_link, runtime->dma_addr, INCR, W32BIT);
-       } else {
-               dma_addr_t asp_dst_pong = iram_dma->addr + ping_size;
-               ram_src_cidx = -ping_size;
-               ram_dst_cidx = ping_size;
-               edma_set_dest(prtd->asp_link[1], asp_dst_pong, INCR, W8BIT);
-
-               edma_set_dest_index(prtd->asp_link[0], data_type,
-                               data_type * fifo_level);
-               edma_set_dest_index(prtd->asp_link[1], data_type,
-                               data_type * fifo_level);
-
-               edma_set_dest(prtd->ram_link, runtime->dma_addr, INCR, W32BIT);
-       }
-
-       if (!fifo_level) {
-               count = ping_size / data_type;
-               edma_set_transfer_params(prtd->asp_link[0], acnt, count,
-                               1, 0, ASYNC);
-               edma_set_transfer_params(prtd->asp_link[1], acnt, count,
-                               1, 0, ASYNC);
-       } else {
-               count = ping_size / (data_type * fifo_level);
-               edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
-                               count, fifo_level, ABSYNC);
-               edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level,
-                               count, fifo_level, ABSYNC);
-       }
-
-       edma_set_src_index(prtd->ram_link, ping_size, ram_src_cidx);
-       edma_set_dest_index(prtd->ram_link, ping_size, ram_dst_cidx);
-       edma_set_transfer_params(prtd->ram_link, ping_size, 2,
-                       runtime->periods, 2, ASYNC);
-
-       /* init master params */
-       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
-       edma_read_slot(prtd->ram_link, &prtd->ram_params);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               struct edmacc_param p_ram;
-               /* Copy entire iram buffer before playback started */
-               prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1);
-               /* 0 dst_bidx */
-               prtd->ram_params.src_dst_bidx = (ping_size << 1);
-               /* 0 dst_cidx */
-               prtd->ram_params.src_dst_cidx = (ping_size << 1);
-               prtd->ram_params.ccnt = 1;
-
-               /* Skip 1st period */
-               edma_read_slot(prtd->ram_link, &p_ram);
-               p_ram.src += (ping_size << 1);
-               p_ram.ccnt -= 1;
-               edma_write_slot(prtd->ram_link2, &p_ram);
-               /*
-                * When 1st started, ram -> iram dma channel will fill the
-                * entire iram.  Then, whenever a ping/pong asp buffer finishes,
-                * 1/2 iram will be filled.
-                */
-               prtd->ram_params.link_bcntrld =
-                       EDMA_CHAN_SLOT(prtd->ram_link2) << 5;
-       }
-       return 0;
-}
-
-/* 1 asp tx or rx channel using 2 parameter channels
- * 1 ram to/from iram channel using 1 parameter channel
- *
- * Playback
- * ram copy channel kicks off first,
- * 1st ram copy of entire iram buffer completion kicks off asp channel
- * asp tcc always kicks off ram copy of 1/2 iram buffer
- *
- * Record
- * asp channel starts, tcc kicks off ram copy
- */
-static int request_ping_pong(struct snd_pcm_substream *substream,
-               struct davinci_runtime_data *prtd,
-               struct snd_dma_buffer *iram_dma)
-{
-       dma_addr_t asp_src_ping;
-       dma_addr_t asp_dst_ping;
-       int ret;
-       struct davinci_pcm_dma_params *params = prtd->params;
-
-       /* Request ram master channel */
-       ret = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
-                                 davinci_pcm_dma_irq, substream,
-                                 prtd->params->ram_chan_q);
-       if (ret < 0)
-               goto exit1;
-
-       /* Request ram link channel */
-       ret = prtd->ram_link = edma_alloc_slot(
-                       EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
-       if (ret < 0)
-               goto exit2;
-
-       ret = prtd->asp_link[1] = edma_alloc_slot(
-                       EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
-       if (ret < 0)
-               goto exit3;
-
-       prtd->ram_link2 = -1;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               ret = prtd->ram_link2 = edma_alloc_slot(
-                       EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
-               if (ret < 0)
-                       goto exit4;
-       }
-       /* circle ping-pong buffers */
-       edma_link(prtd->asp_link[0], prtd->asp_link[1]);
-       edma_link(prtd->asp_link[1], prtd->asp_link[0]);
-       /* circle ram buffers */
-       edma_link(prtd->ram_link, prtd->ram_link);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               asp_src_ping = iram_dma->addr;
-               asp_dst_ping = params->dma_addr;        /* fifo */
-       } else {
-               asp_src_ping = params->dma_addr;        /* fifo */
-               asp_dst_ping = iram_dma->addr;
-       }
-       /* ping */
-       edma_set_src(prtd->asp_link[0], asp_src_ping, INCR, W16BIT);
-       edma_set_dest(prtd->asp_link[0], asp_dst_ping, INCR, W16BIT);
-       edma_set_src_index(prtd->asp_link[0], 0, 0);
-       edma_set_dest_index(prtd->asp_link[0], 0, 0);
-
-       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
-       prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
-       prtd->asp_params.opt |= TCCHEN |
-               EDMA_TCC(prtd->ram_channel & 0x3f);
-       edma_write_slot(prtd->asp_link[0], &prtd->asp_params);
-
-       /* pong */
-       edma_set_src(prtd->asp_link[1], asp_src_ping, INCR, W16BIT);
-       edma_set_dest(prtd->asp_link[1], asp_dst_ping, INCR, W16BIT);
-       edma_set_src_index(prtd->asp_link[1], 0, 0);
-       edma_set_dest_index(prtd->asp_link[1], 0, 0);
-
-       edma_read_slot(prtd->asp_link[1], &prtd->asp_params);
-       prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
-       /* interrupt after every pong completion */
-       prtd->asp_params.opt |= TCINTEN | TCCHEN |
-               EDMA_TCC(prtd->ram_channel & 0x3f);
-       edma_write_slot(prtd->asp_link[1], &prtd->asp_params);
-
-       /* ram */
-       edma_set_src(prtd->ram_link, iram_dma->addr, INCR, W32BIT);
-       edma_set_dest(prtd->ram_link, iram_dma->addr, INCR, W32BIT);
-       pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u,"
-               "for asp:%u %u %u\n", __func__,
-               prtd->ram_channel, prtd->ram_link, prtd->ram_link2,
-               prtd->asp_channel, prtd->asp_link[0],
-               prtd->asp_link[1]);
-       return 0;
-exit4:
-       edma_free_channel(prtd->asp_link[1]);
-       prtd->asp_link[1] = -1;
-exit3:
-       edma_free_channel(prtd->ram_link);
-       prtd->ram_link = -1;
-exit2:
-       edma_free_channel(prtd->ram_channel);
-       prtd->ram_channel = -1;
-exit1:
-       return ret;
-}
-
-static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
-{
-       struct snd_dma_buffer *iram_dma;
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct davinci_pcm_dma_params *params = prtd->params;
-       int ret;
-
-       if (!params)
-               return -ENODEV;
-
-       /* Request asp master DMA channel */
-       ret = prtd->asp_channel = edma_alloc_channel(params->channel,
-                       davinci_pcm_dma_irq, substream,
-                       prtd->params->asp_chan_q);
-       if (ret < 0)
-               goto exit1;
-
-       /* Request asp link channels */
-       ret = prtd->asp_link[0] = edma_alloc_slot(
-                       EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
-       if (ret < 0)
-               goto exit2;
-
-       iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data;
-       if (iram_dma) {
-               if (request_ping_pong(substream, prtd, iram_dma) == 0)
-                       return 0;
-               printk(KERN_WARNING "%s: dma channel allocation failed,"
-                               "not using sram\n", __func__);
-       }
-
-       /* Issue transfer completion IRQ when the channel completes a
-        * transfer, then always reload from the same slot (by a kind
-        * of loopback link).  The completion IRQ handler will update
-        * the reload slot with a new buffer.
-        *
-        * REVISIT save p_ram here after setting up everything except
-        * the buffer and its length (ccnt) ... use it as a template
-        * so davinci_pcm_enqueue_dma() takes less time in IRQ.
-        */
-       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
-       prtd->asp_params.opt |= TCINTEN |
-               EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel));
-       prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5;
-       edma_write_slot(prtd->asp_link[0], &prtd->asp_params);
-       return 0;
-exit2:
-       edma_free_channel(prtd->asp_channel);
-       prtd->asp_channel = -1;
-exit1:
-       return ret;
-}
-
-static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       int ret = 0;
-
-       spin_lock(&prtd->lock);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               edma_start(prtd->asp_channel);
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-                   prtd->ram_channel >= 0) {
-                       /* copy 1st iram buffer */
-                       edma_start(prtd->ram_channel);
-               }
-               break;
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               edma_resume(prtd->asp_channel);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               edma_pause(prtd->asp_channel);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       spin_unlock(&prtd->lock);
-
-       return ret;
-}
-
-static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-
-       davinci_pcm_period_reset(substream);
-       if (prtd->ram_channel >= 0) {
-               int ret = ping_pong_dma_setup(substream);
-               if (ret < 0)
-                       return ret;
-
-               edma_write_slot(prtd->ram_channel, &prtd->ram_params);
-               edma_write_slot(prtd->asp_channel, &prtd->asp_params);
-
-               print_buf_info(prtd->ram_channel, "ram_channel");
-               print_buf_info(prtd->ram_link, "ram_link");
-               print_buf_info(prtd->ram_link2, "ram_link2");
-               print_buf_info(prtd->asp_channel, "asp_channel");
-               print_buf_info(prtd->asp_link[0], "asp_link[0]");
-               print_buf_info(prtd->asp_link[1], "asp_link[1]");
-
-               /*
-                * There is a phase offset of 2 periods between the position
-                * used by dma setup and the position reported in the pointer
-                * function.
-                *
-                * The phase offset, when not using ping-pong buffers, is due to
-                * the two consecutive calls to davinci_pcm_enqueue_dma() below.
-                *
-                * Whereas here, with ping-pong buffers, the phase is due to
-                * there being an entire buffer transfer complete before the
-                * first dma completion event triggers davinci_pcm_dma_irq().
-                */
-               davinci_pcm_period_elapsed(substream);
-               davinci_pcm_period_elapsed(substream);
-
-               return 0;
-       }
-       davinci_pcm_enqueue_dma(substream);
-       davinci_pcm_period_elapsed(substream);
-
-       /* Copy self-linked parameter RAM entry into master channel */
-       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
-       edma_write_slot(prtd->asp_channel, &prtd->asp_params);
-       davinci_pcm_enqueue_dma(substream);
-       davinci_pcm_period_elapsed(substream);
-
-       return 0;
-}
-
-static snd_pcm_uframes_t
-davinci_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct davinci_runtime_data *prtd = runtime->private_data;
-       unsigned int offset;
-       int asp_count;
-       unsigned int period_size = snd_pcm_lib_period_bytes(substream);
-
-       /*
-        * There is a phase offset of 2 periods between the position used by dma
-        * setup and the position reported in the pointer function. Either +2 in
-        * the dma setup or -2 here in the pointer function (with wrapping,
-        * both) accounts for this offset -- choose the latter since it makes
-        * the first-time setup clearer.
-        */
-       spin_lock(&prtd->lock);
-       asp_count = prtd->period - 2;
-       spin_unlock(&prtd->lock);
-
-       if (asp_count < 0)
-               asp_count += runtime->periods;
-       asp_count *= period_size;
-
-       offset = bytes_to_frames(runtime, asp_count);
-       if (offset >= runtime->buffer_size)
-               offset = 0;
-
-       return offset;
-}
-
-static int davinci_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct davinci_runtime_data *prtd;
-       struct snd_pcm_hardware *ppcm;
-       int ret = 0;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct davinci_pcm_dma_params *pa;
-       struct davinci_pcm_dma_params *params;
-
-       pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       if (!pa)
-               return -ENODEV;
-       params = &pa[substream->stream];
-
-       ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                       &pcm_hardware_playback : &pcm_hardware_capture;
-       allocate_sram(substream, params->sram_pool, params->sram_size, ppcm);
-       snd_soc_set_runtime_hwparams(substream, ppcm);
-       /* ensure that buffer size is a multiple of period size */
-       ret = snd_pcm_hw_constraint_integer(runtime,
-                                               SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0)
-               return ret;
-
-       prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL);
-       if (prtd == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&prtd->lock);
-       prtd->params = params;
-       prtd->asp_channel = -1;
-       prtd->asp_link[0] = prtd->asp_link[1] = -1;
-       prtd->ram_channel = -1;
-       prtd->ram_link = -1;
-       prtd->ram_link2 = -1;
-
-       runtime->private_data = prtd;
-
-       ret = davinci_pcm_dma_request(substream);
-       if (ret) {
-               printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n");
-               kfree(prtd);
-       }
-
-       return ret;
-}
-
-static int davinci_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct davinci_runtime_data *prtd = runtime->private_data;
-
-       if (prtd->ram_channel >= 0)
-               edma_stop(prtd->ram_channel);
-       if (prtd->asp_channel >= 0)
-               edma_stop(prtd->asp_channel);
-       if (prtd->asp_link[0] >= 0)
-               edma_unlink(prtd->asp_link[0]);
-       if (prtd->asp_link[1] >= 0)
-               edma_unlink(prtd->asp_link[1]);
-       if (prtd->ram_link >= 0)
-               edma_unlink(prtd->ram_link);
-
-       if (prtd->asp_link[0] >= 0)
-               edma_free_slot(prtd->asp_link[0]);
-       if (prtd->asp_link[1] >= 0)
-               edma_free_slot(prtd->asp_link[1]);
-       if (prtd->asp_channel >= 0)
-               edma_free_channel(prtd->asp_channel);
-       if (prtd->ram_link >= 0)
-               edma_free_slot(prtd->ram_link);
-       if (prtd->ram_link2 >= 0)
-               edma_free_slot(prtd->ram_link2);
-       if (prtd->ram_channel >= 0)
-               edma_free_channel(prtd->ram_channel);
-
-       kfree(prtd);
-
-       return 0;
-}
-
-static int davinci_pcm_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *hw_params)
-{
-       return snd_pcm_lib_malloc_pages(substream,
-                                       params_buffer_bytes(hw_params));
-}
-
-static int davinci_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static int davinci_pcm_mmap(struct snd_pcm_substream *substream,
-                           struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops davinci_pcm_ops = {
-       .open =         davinci_pcm_open,
-       .close =        davinci_pcm_close,
-       .ioctl =        snd_pcm_lib_ioctl,
-       .hw_params =    davinci_pcm_hw_params,
-       .hw_free =      davinci_pcm_hw_free,
-       .prepare =      davinci_pcm_prepare,
-       .trigger =      davinci_pcm_trigger,
-       .pointer =      davinci_pcm_pointer,
-       .mmap =         davinci_pcm_mmap,
-};
-
-static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
-               size_t size)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-
-       pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, "
-               "size=%d\n", (void *) buf->area, (void *) buf->addr, size);
-
-       if (!buf->area)
-               return -ENOMEM;
-
-       buf->bytes = size;
-       return 0;
-}
-
-static void davinci_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               struct snd_dma_buffer *iram_dma;
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                                     buf->area, buf->addr);
-               buf->area = NULL;
-               iram_dma = buf->private_data;
-               if (iram_dma) {
-                       davinci_free_sram(substream, iram_dma);
-                       kfree(iram_dma);
-               }
-       }
-}
-
-static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret;
-
-       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = davinci_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK,
-                       pcm_hardware_playback.buffer_bytes_max);
-               if (ret)
-                       return ret;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = davinci_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE,
-                       pcm_hardware_capture.buffer_bytes_max);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_platform_driver davinci_soc_platform = {
-       .ops =          &davinci_pcm_ops,
-       .pcm_new =      davinci_pcm_new,
-       .pcm_free =     davinci_pcm_free,
-};
-
-int davinci_soc_platform_register(struct device *dev)
-{
-       return devm_snd_soc_register_platform(dev, &davinci_soc_platform);
-}
-EXPORT_SYMBOL_GPL(davinci_soc_platform_register);
-
-MODULE_AUTHOR("Vladimir Barinov");
-MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
deleted file mode 100644 (file)
index 0fe2346..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * ALSA PCM interface for the TI DAVINCI processor
- *
- * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _DAVINCI_PCM_H
-#define _DAVINCI_PCM_H
-
-#include <linux/genalloc.h>
-#include <linux/platform_data/davinci_asp.h>
-#include <linux/platform_data/edma.h>
-
-struct davinci_pcm_dma_params {
-       int channel;                    /* sync dma channel ID */
-       unsigned short acnt;
-       dma_addr_t dma_addr;            /* device physical address for DMA */
-       unsigned sram_size;
-       struct gen_pool *sram_pool;     /* SRAM gen_pool for ping pong */
-       enum dma_event_q asp_chan_q;    /* event queue number for ASP channel */
-       enum dma_event_q ram_chan_q;    /* event queue number for RAM channel */
-       unsigned char data_type;        /* xfer data type */
-       unsigned char convert_mono_stereo;
-       unsigned int fifo_level;
-};
-
-#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC)
-int davinci_soc_platform_register(struct device *dev);
-#else
-static inline int davinci_soc_platform_register(struct device *dev)
-{
-       return 0;
-}
-#endif /* CONFIG_SND_DAVINCI_SOC */
-
-#endif
index 5bee042..fabd05f 100644 (file)
@@ -33,8 +33,9 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
-#include "davinci-pcm.h"
+#include "edma-pcm.h"
 #include "davinci-i2s.h"
 
 #define MOD_REG_BIT(val, mask, set) do { \
@@ -47,7 +48,8 @@
 
 struct davinci_vcif_dev {
        struct davinci_vc *davinci_vc;
-       struct davinci_pcm_dma_params   dma_params[2];
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       int dma_request[2];
 };
 
 static void davinci_vcif_start(struct snd_pcm_substream *substream)
@@ -93,8 +95,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
 {
        struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
        struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
-       struct davinci_pcm_dma_params *dma_params =
-                       &davinci_vcif_dev->dma_params[substream->stream];
        u32 w;
 
        /* Restart the codec before setup */
@@ -113,16 +113,12 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
        /* Determine xfer data type */
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_U8:
-               dma_params->data_type = 0;
-
                MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
                            DAVINCI_VC_CTRL_RD_UNSIGNED |
                            DAVINCI_VC_CTRL_WD_BITS_8 |
                            DAVINCI_VC_CTRL_WD_UNSIGNED, 1);
                break;
        case SNDRV_PCM_FORMAT_S8:
-               dma_params->data_type = 1;
-
                MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
                            DAVINCI_VC_CTRL_WD_BITS_8, 1);
 
@@ -130,8 +126,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
                            DAVINCI_VC_CTRL_WD_UNSIGNED, 0);
                break;
        case SNDRV_PCM_FORMAT_S16_LE:
-               dma_params->data_type = 2;
-
                MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
                            DAVINCI_VC_CTRL_RD_UNSIGNED |
                            DAVINCI_VC_CTRL_WD_BITS_8 |
@@ -142,8 +136,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       dma_params->acnt  = dma_params->data_type;
-
        writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
 
        return 0;
@@ -172,24 +164,25 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
-static int davinci_vcif_startup(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
-       return 0;
-}
-
 #define DAVINCI_VCIF_RATES     SNDRV_PCM_RATE_8000_48000
 
 static const struct snd_soc_dai_ops davinci_vcif_dai_ops = {
-       .startup        = davinci_vcif_startup,
        .trigger        = davinci_vcif_trigger,
        .hw_params      = davinci_vcif_hw_params,
 };
 
+static int davinci_vcif_dai_probe(struct snd_soc_dai *dai)
+{
+       struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+       return 0;
+}
+
 static struct snd_soc_dai_driver davinci_vcif_dai = {
+       .probe = davinci_vcif_dai_probe,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -225,16 +218,16 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 
        /* DMA tx params */
        davinci_vcif_dev->davinci_vc = davinci_vc;
-       davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel =
-                                       davinci_vc->davinci_vcif.dma_tx_channel;
-       davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
-                                       davinci_vc->davinci_vcif.dma_tx_addr;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data =
+                               &davinci_vc->davinci_vcif.dma_tx_channel;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
+                               davinci_vc->davinci_vcif.dma_tx_addr;
 
        /* DMA rx params */
-       davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel =
-                                       davinci_vc->davinci_vcif.dma_rx_channel;
-       davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
-                                       davinci_vc->davinci_vcif.dma_rx_addr;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data =
+                               &davinci_vc->davinci_vcif.dma_rx_channel;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
+                               davinci_vc->davinci_vcif.dma_rx_addr;
 
        dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
 
@@ -245,7 +238,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = davinci_soc_platform_register(&pdev->dev);
+       ret = edma_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
                snd_soc_unregister_component(&pdev->dev);
index 3f6959c..de43887 100644 (file)
@@ -512,6 +512,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        memcpy(priv->dai_link, fsl_asoc_card_dai,
               sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
 
+       ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+               goto asrc_fail;
+       }
+
        /* Normal DAI Link */
        priv->dai_link[0].cpu_of_node = cpu_np;
        priv->dai_link[0].codec_of_node = codec_np;
index 75870c0..91eb3ae 100644 (file)
@@ -1049,7 +1049,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
                                enum spdif_txrate index, bool round)
 {
        const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
-       bool is_sysclk = clk == spdif_priv->sysclk;
+       bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
        u64 rate_ideal, rate_actual, sub;
        u32 sysclk_dfmin, sysclk_dfmax;
        u32 txclk_df, sysclk_df, arate;
@@ -1143,7 +1143,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
                        spdif_priv->txclk_src[index], rate[index]);
        dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n",
                        spdif_priv->txclk_df[index], rate[index]);
-       if (spdif_priv->txclk[index] == spdif_priv->sysclk)
+       if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk))
                dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n",
                                spdif_priv->sysclk_df[index], rate[index]);
        dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n",
index 2595611..6b0c8f7 100644 (file)
@@ -603,17 +603,20 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
        factor = (div2 + 1) * (7 * psr + 1) * 2;
 
        for (i = 0; i < 255; i++) {
-               /* The bclk rate must be smaller than 1/5 sysclk rate */
-               if (factor * (i + 1) < 5)
-                       continue;
-
-               tmprate = freq * factor * (i + 2);
+               tmprate = freq * factor * (i + 1);
 
                if (baudclk_is_used)
                        clkrate = clk_get_rate(ssi_private->baudclk);
                else
                        clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
 
+               /*
+                * Hardware limitation: The bclk rate must be
+                * never greater than 1/5 IPG clock rate
+                */
+               if (clkrate * 5 > clk_get_rate(ssi_private->clk))
+                       continue;
+
                clkrate /= factor;
                afreq = clkrate / (i + 1);
 
@@ -1224,7 +1227,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
        ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0;
        ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0;
 
-       ret = !of_property_read_u32_array(np, "dmas", dmas, 4);
+       ret = of_property_read_u32_array(np, "dmas", dmas, 4);
        if (ssi_private->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
                ssi_private->use_dual_fifo = true;
                /* When using dual fifo mode, we need to keep watermark
index f8cf10e..20e7400 100644 (file)
@@ -53,9 +53,9 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
 
        /* Headphone jack detection */
        if (gpio_is_valid(data->jack_gpio)) {
-               ret = snd_soc_jack_new(rtd->codec, "Headphone",
-                                      SND_JACK_HEADPHONE | SND_JACK_BTN_0,
-                                      &headset_jack);
+               ret = snd_soc_card_jack_new(rtd->card, "Headphone",
+                                           SND_JACK_HEADPHONE | SND_JACK_BTN_0,
+                                           &headset_jack, NULL, 0);
                if (ret)
                        return ret;
 
index a958937..0653aa8 100644 (file)
@@ -205,16 +205,14 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        /* Headphone jack detection */
-       snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
-       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
-                             hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE,
+                             &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
        wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
 
        /* Microphone jack detection */
-       snd_soc_jack_new(codec, "Microphone",
-                        SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack);
-       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
-                             mic_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Microphone",
+                             SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack,
+                             mic_jack_pins, ARRAY_SIZE(mic_jack_pins));
        wm8350_mic_jack_detect(codec, &mic_jack, SND_JACK_MICROPHONE,
                               SND_JACK_BTN_0);
 
index f7c6734..c49a408 100644 (file)
@@ -176,11 +176,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
 
        if (gpio_is_valid(priv->gpio_hp_det)) {
-               snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE,
-                                &simple_card_hp_jack);
-               snd_soc_jack_add_pins(&simple_card_hp_jack,
-                                     ARRAY_SIZE(simple_card_hp_jack_pins),
-                                     simple_card_hp_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Headphones",
+                                     SND_JACK_HEADPHONE,
+                                     &simple_card_hp_jack,
+                                     simple_card_hp_jack_pins,
+                                     ARRAY_SIZE(simple_card_hp_jack_pins));
 
                simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
                simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert;
@@ -189,11 +189,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        if (gpio_is_valid(priv->gpio_mic_det)) {
-               snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE,
-                                &simple_card_mic_jack);
-               snd_soc_jack_add_pins(&simple_card_mic_jack,
-                                     ARRAY_SIZE(simple_card_mic_jack_pins),
-                                     simple_card_mic_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Mic Jack",
+                                     SND_JACK_MICROPHONE,
+                                     &simple_card_mic_jack,
+                                     simple_card_mic_jack_pins,
+                                     ARRAY_SIZE(simple_card_mic_jack_pins));
                simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
                simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert;
                snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
@@ -372,6 +372,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
                            strlen(dai_link->cpu_dai_name)   +
                            strlen(dai_link->codec_dai_name) + 2,
                            GFP_KERNEL);
+       if (!name) {
+               ret = -ENOMEM;
+               goto dai_link_of_err;
+       }
+
        sprintf(name, "%s-%s", dai_link->cpu_dai_name,
                                dai_link->codec_dai_name);
        dai_link->name = dai_link->stream_name = name;
index a8e53c4..cd9aee9 100644 (file)
@@ -1,42 +1,10 @@
 # Core support
-snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
-snd-soc-sst-acpi-objs := sst-acpi.o
-
-snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \
-       sst-mfld-platform-compress.o sst-atom-controls.o
-snd-soc-mfld-machine-objs := mfld_machine.o
-
-obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
-obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o
-
-obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o
-obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
+obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
 
 # Platform Support
-snd-soc-sst-haswell-pcm-objs := \
-       sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o
-snd-soc-sst-baytrail-pcm-objs := \
-       sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o
-
-obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o
-obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
+obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
+obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
+obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += atom/
 
 # Machine support
-snd-soc-sst-haswell-objs := haswell.o
-snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
-snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
-snd-soc-sst-broadwell-objs := broadwell.o
-snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o
-snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
-snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
-
-obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
-obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
-obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
-obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
-obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o
-obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
-obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
-
-# DSP driver
-obj-$(CONFIG_SND_SST_IPC) += sst/
+obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/
diff --git a/sound/soc/intel/atom/Makefile b/sound/soc/intel/atom/Makefile
new file mode 100644 (file)
index 0000000..ce8074f
--- /dev/null
@@ -0,0 +1,7 @@
+snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \
+               sst-mfld-platform-compress.o sst-atom-controls.o
+
+obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
+
+# DSP driver
+obj-$(CONFIG_SND_SST_IPC) += sst/
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
new file mode 100644 (file)
index 0000000..90aa5c0
--- /dev/null
@@ -0,0 +1,1422 @@
+/*
+ *  sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
+ *
+ *  Copyright (C) 2013-14 Intel Corp
+ *  Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
+ *     Vinod Koul <vinod.koul@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  In the dpcm driver modelling when a particular FE/BE/Mixer/Pipe is active
+ *  we forward the settings and parameters, rest we keep the values  in
+ *  driver and forward when DAPM enables them
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "sst-mfld-platform.h"
+#include "sst-atom-controls.h"
+
+static int sst_fill_byte_control(struct sst_data *drv,
+                                        u8 ipc_msg, u8 block,
+                                        u8 task_id, u8 pipe_id,
+                                        u16 len, void *cmd_data)
+{
+       struct snd_sst_bytes_v2 *byte_data = drv->byte_stream;
+
+       byte_data->type = SST_CMD_BYTES_SET;
+       byte_data->ipc_msg = ipc_msg;
+       byte_data->block = block;
+       byte_data->task_id = task_id;
+       byte_data->pipe_id = pipe_id;
+
+       if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) {
+               dev_err(&drv->pdev->dev, "command length too big (%u)", len);
+               return -EINVAL;
+       }
+       byte_data->len = len;
+       memcpy(byte_data->bytes, cmd_data, len);
+       print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET,
+                            byte_data, len + sizeof(*byte_data));
+       return 0;
+}
+
+static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
+                                u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+                                void *cmd_data, u16 len)
+{
+       int ret = 0;
+
+       ret = sst_fill_byte_control(drv, ipc_msg,
+                               block, task_id, pipe_id, len, cmd_data);
+       if (ret < 0)
+               return ret;
+       return sst->ops->send_byte_stream(sst->dev, drv->byte_stream);
+}
+
+/**
+ * sst_fill_and_send_cmd - generate the IPC message and send it to the FW
+ * @ipc_msg:   type of IPC (CMD, SET_PARAMS, GET_PARAMS)
+ * @cmd_data:  the IPC payload
+ */
+static int sst_fill_and_send_cmd(struct sst_data *drv,
+                                u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+                                void *cmd_data, u16 len)
+{
+       int ret;
+
+       mutex_lock(&drv->lock);
+       ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
+                                       task_id, pipe_id, cmd_data, len);
+       mutex_unlock(&drv->lock);
+
+       return ret;
+}
+
+/**
+ * tx map value is a bitfield where each bit represents a FW channel
+ *
+ *                     3 2 1 0         # 0 = codec0, 1 = codec1
+ *                     RLRLRLRL        # 3, 4 = reserved
+ *
+ * e.g. slot 0 rx map =        00001100b -> data from slot 0 goes into codec_in1 L,R
+ */
+static u8 sst_ssp_tx_map[SST_MAX_TDM_SLOTS] = {
+       0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default rx map */
+};
+
+/**
+ * rx map value is a bitfield where each bit represents a slot
+ *
+ *                       76543210      # 0 = slot 0, 1 = slot 1
+ *
+ * e.g. codec1_0 tx map = 00000101b -> data from codec_out1_0 goes into slot 0, 2
+ */
+static u8 sst_ssp_rx_map[SST_MAX_TDM_SLOTS] = {
+       0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default tx map */
+};
+
+/**
+ * NOTE: this is invoked with lock held
+ */
+static int sst_send_slot_map(struct sst_data *drv)
+{
+       struct sst_param_sba_ssp_slot_map cmd;
+
+       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+       cmd.header.command_id = SBA_SET_SSP_SLOT_MAP;
+       cmd.header.length = sizeof(struct sst_param_sba_ssp_slot_map)
+                               - sizeof(struct sst_dsp_header);
+
+       cmd.param_id = SBA_SET_SSP_SLOT_MAP;
+       cmd.param_len = sizeof(cmd.rx_slot_map) + sizeof(cmd.tx_slot_map)
+                                       + sizeof(cmd.ssp_index);
+       cmd.ssp_index = SSP_CODEC;
+
+       memcpy(cmd.rx_slot_map, &sst_ssp_tx_map[0], sizeof(cmd.rx_slot_map));
+       memcpy(cmd.tx_slot_map, &sst_ssp_rx_map[0], sizeof(cmd.tx_slot_map));
+
+       return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+                       SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
+                             sizeof(cmd.header) + cmd.header.length);
+}
+
+int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_info *uinfo)
+{
+       struct sst_enum *e = (struct sst_enum *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = e->max;
+
+       if (uinfo->value.enumerated.item > e->max - 1)
+               uinfo->value.enumerated.item = e->max - 1;
+       strcpy(uinfo->value.enumerated.name,
+               e->texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+/**
+ * sst_slot_get - get the status of the interleaver/deinterleaver control
+ *
+ * Searches the map where the control status is stored, and gets the
+ * channel/slot which is currently set for this enumerated control. Since it is
+ * an enumerated control, there is only one possible value.
+ */
+static int sst_slot_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct sst_enum *e = (void *)kcontrol->private_value;
+       struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+       struct sst_data *drv = snd_soc_component_get_drvdata(c);
+       unsigned int ctl_no = e->reg;
+       unsigned int is_tx = e->tx;
+       unsigned int val, mux;
+       u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
+
+       mutex_lock(&drv->lock);
+       val = 1 << ctl_no;
+       /* search which slot/channel has this bit set - there should be only one */
+       for (mux = e->max; mux > 0;  mux--)
+               if (map[mux - 1] & val)
+                       break;
+
+       ucontrol->value.enumerated.item[0] = mux;
+       mutex_unlock(&drv->lock);
+
+       dev_dbg(c->dev, "%s - %s map = %#x\n",
+                       is_tx ? "tx channel" : "rx slot",
+                        e->texts[mux], mux ? map[mux - 1] : -1);
+       return 0;
+}
+
+/* sst_check_and_send_slot_map - helper for checking power state and sending
+ * slot map cmd
+ *
+ * called with lock held
+ */
+static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol *kcontrol)
+{
+       struct sst_enum *e = (void *)kcontrol->private_value;
+       int ret = 0;
+
+       if (e->w && e->w->power)
+               ret = sst_send_slot_map(drv);
+       else
+               dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n",
+                               kcontrol->id.name);
+       return ret;
+}
+
+/**
+ * sst_slot_put - set the status of interleaver/deinterleaver control
+ *
+ * (de)interleaver controls are defined in opposite sense to be user-friendly
+ *
+ * Instead of the enum value being the value written to the register, it is the
+ * register address; and the kcontrol number (register num) is the value written
+ * to the register. This is so that there can be only one value for each
+ * slot/channel since there is only one control for each slot/channel.
+ *
+ * This means that whenever an enum is set, we need to clear the bit
+ * for that kcontrol_no for all the interleaver OR deinterleaver registers
+ */
+static int sst_slot_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+       struct sst_data *drv = snd_soc_component_get_drvdata(c);
+       struct sst_enum *e = (void *)kcontrol->private_value;
+       int i, ret = 0;
+       unsigned int ctl_no = e->reg;
+       unsigned int is_tx = e->tx;
+       unsigned int slot_channel_no;
+       unsigned int val, mux;
+       u8 *map;
+
+       map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
+
+       val = 1 << ctl_no;
+       mux = ucontrol->value.enumerated.item[0];
+       if (mux > e->max - 1)
+               return -EINVAL;
+
+       mutex_lock(&drv->lock);
+       /* first clear all registers of this bit */
+       for (i = 0; i < e->max; i++)
+               map[i] &= ~val;
+
+       if (mux == 0) {
+               /* kctl set to 'none' and we reset the bits so send IPC */
+               ret = sst_check_and_send_slot_map(drv, kcontrol);
+
+               mutex_unlock(&drv->lock);
+               return ret;
+       }
+
+       /* offset by one to take "None" into account */
+       slot_channel_no = mux - 1;
+       map[slot_channel_no] |= val;
+
+       dev_dbg(c->dev, "%s %s map = %#x\n",
+                       is_tx ? "tx channel" : "rx slot",
+                       e->texts[mux], map[slot_channel_no]);
+
+       ret = sst_check_and_send_slot_map(drv, kcontrol);
+
+       mutex_unlock(&drv->lock);
+       return ret;
+}
+
+static int sst_send_algo_cmd(struct sst_data *drv,
+                             struct sst_algo_control *bc)
+{
+       int len, ret = 0;
+       struct sst_cmd_set_params *cmd;
+
+       /*bc->max includes sizeof algos + length field*/
+       len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max;
+
+       cmd = kzalloc(len, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id);
+       cmd->command_id = bc->cmd_id;
+       memcpy(cmd->params, bc->params, bc->max);
+
+       ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+                               SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len);
+       kfree(cmd);
+       return ret;
+}
+
+/**
+ * sst_find_and_send_pipe_algo - send all the algo parameters for a pipe
+ *
+ * The algos which are in each pipeline are sent to the firmware one by one
+ *
+ * Called with lock held
+ */
+static int sst_find_and_send_pipe_algo(struct sst_data *drv,
+                                       const char *pipe, struct sst_ids *ids)
+{
+       int ret = 0;
+       struct sst_algo_control *bc;
+       struct sst_module *algo = NULL;
+
+       dev_dbg(&drv->pdev->dev, "Enter: widget=%s\n", pipe);
+
+       list_for_each_entry(algo, &ids->algo_list, node) {
+               bc = (void *)algo->kctl->private_value;
+
+               dev_dbg(&drv->pdev->dev, "Found algo control name=%s pipe=%s\n",
+                               algo->kctl->id.name, pipe);
+               ret = sst_send_algo_cmd(drv, bc);
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
+
+static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = bc->max;
+
+       return 0;
+}
+
+static int sst_algo_control_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+
+       switch (bc->type) {
+       case SST_ALGO_PARAMS:
+               memcpy(ucontrol->value.bytes.data, bc->params, bc->max);
+               break;
+       default:
+               dev_err(component->dev, "Invalid Input- algo type:%d\n",
+                               bc->type);
+               return -EINVAL;
+
+       }
+       return 0;
+}
+
+static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       int ret = 0;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+       dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
+       mutex_lock(&drv->lock);
+       switch (bc->type) {
+       case SST_ALGO_PARAMS:
+               memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
+               break;
+       default:
+               mutex_unlock(&drv->lock);
+               dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
+                               bc->type);
+               return -EINVAL;
+       }
+       /*if pipe is enabled, need to send the algo params from here*/
+       if (bc->w && bc->w->power)
+               ret = sst_send_algo_cmd(drv, bc);
+       mutex_unlock(&drv->lock);
+
+       return ret;
+}
+
+static int sst_gain_ctl_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = mc->stereo ? 2 : 1;
+       uinfo->value.integer.min = mc->min;
+       uinfo->value.integer.max = mc->max;
+
+       return 0;
+}
+
+/**
+ * sst_send_gain_cmd - send the gain algorithm IPC to the FW
+ * @gv:                the stored value of gain (also contains rampduration)
+ * @mute:      flag that indicates whether this was called from the
+ *             digital_mute callback or directly. If called from the
+ *             digital_mute callback, module will be muted/unmuted based on this
+ *             flag. The flag is always 0 if called directly.
+ *
+ * Called with sst_data.lock held
+ *
+ * The user-set gain value is sent only if the user-controllable 'mute' control
+ * is OFF (indicated by gv->mute). Otherwise, the mute value (MIN value) is
+ * sent.
+ */
+static int sst_send_gain_cmd(struct sst_data *drv, struct sst_gain_value *gv,
+                             u16 task_id, u16 loc_id, u16 module_id, int mute)
+{
+       struct sst_cmd_set_gain_dual cmd;
+
+       dev_dbg(&drv->pdev->dev, "Enter\n");
+
+       cmd.header.command_id = MMX_SET_GAIN;
+       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+       cmd.gain_cell_num = 1;
+
+       if (mute || gv->mute) {
+               cmd.cell_gains[0].cell_gain_left = SST_GAIN_MIN_VALUE;
+               cmd.cell_gains[0].cell_gain_right = SST_GAIN_MIN_VALUE;
+       } else {
+               cmd.cell_gains[0].cell_gain_left = gv->l_gain;
+               cmd.cell_gains[0].cell_gain_right = gv->r_gain;
+       }
+
+       SST_FILL_DESTINATION(2, cmd.cell_gains[0].dest,
+                            loc_id, module_id);
+       cmd.cell_gains[0].gain_time_constant = gv->ramp_duration;
+
+       cmd.header.length = sizeof(struct sst_cmd_set_gain_dual)
+                               - sizeof(struct sst_dsp_header);
+
+       /* we are with lock held, so call the unlocked api  to send */
+       return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+                               SST_FLAG_BLOCKED, task_id, 0, &cmd,
+                             sizeof(cmd.header) + cmd.header.length);
+}
+
+static int sst_gain_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
+       struct sst_gain_value *gv = mc->gain_val;
+
+       switch (mc->type) {
+       case SST_GAIN_TLV:
+               ucontrol->value.integer.value[0] = gv->l_gain;
+               ucontrol->value.integer.value[1] = gv->r_gain;
+               break;
+
+       case SST_GAIN_MUTE:
+               ucontrol->value.integer.value[0] = gv->mute ? 1 : 0;
+               break;
+
+       case SST_GAIN_RAMP_DURATION:
+               ucontrol->value.integer.value[0] = gv->ramp_duration;
+               break;
+
+       default:
+               dev_err(component->dev, "Invalid Input- gain type:%d\n",
+                               mc->type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int sst_gain_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       int ret = 0;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+       struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
+       struct sst_gain_value *gv = mc->gain_val;
+
+       mutex_lock(&drv->lock);
+
+       switch (mc->type) {
+       case SST_GAIN_TLV:
+               gv->l_gain = ucontrol->value.integer.value[0];
+               gv->r_gain = ucontrol->value.integer.value[1];
+               dev_dbg(cmpnt->dev, "%s: Volume %d, %d\n",
+                               mc->pname, gv->l_gain, gv->r_gain);
+               break;
+
+       case SST_GAIN_MUTE:
+               gv->mute = !!ucontrol->value.integer.value[0];
+               dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute);
+               break;
+
+       case SST_GAIN_RAMP_DURATION:
+               gv->ramp_duration = ucontrol->value.integer.value[0];
+               dev_dbg(cmpnt->dev, "%s: Ramp Delay%d\n",
+                                       mc->pname, gv->ramp_duration);
+               break;
+
+       default:
+               mutex_unlock(&drv->lock);
+               dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n",
+                               mc->type);
+               return -EINVAL;
+       }
+
+       if (mc->w && mc->w->power)
+               ret = sst_send_gain_cmd(drv, gv, mc->task_id,
+                       mc->pipe_id | mc->instance_id, mc->module_id, 0);
+       mutex_unlock(&drv->lock);
+
+       return ret;
+}
+
+static int sst_set_pipe_gain(struct sst_ids *ids,
+                               struct sst_data *drv, int mute);
+
+static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol)
+{
+       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+       struct sst_data *drv = snd_soc_component_get_drvdata(c);
+       struct sst_ids *ids = w->priv;
+
+       mutex_lock(&drv->lock);
+       sst_find_and_send_pipe_algo(drv, w->name, ids);
+       sst_set_pipe_gain(ids, drv, 0);
+       mutex_unlock(&drv->lock);
+
+       return 0;
+}
+
+static int sst_generic_modules_event(struct snd_soc_dapm_widget *w,
+                                    struct snd_kcontrol *k, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               return sst_send_pipe_module_params(w, k);
+       return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10, 10, 0);
+
+/* Look up table to convert MIXER SW bit regs to SWM inputs */
+static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = {
+       [SST_IP_CODEC0]         = SST_SWM_IN_CODEC0,
+       [SST_IP_CODEC1]         = SST_SWM_IN_CODEC1,
+       [SST_IP_LOOP0]          = SST_SWM_IN_SPROT_LOOP,
+       [SST_IP_LOOP1]          = SST_SWM_IN_MEDIA_LOOP1,
+       [SST_IP_LOOP2]          = SST_SWM_IN_MEDIA_LOOP2,
+       [SST_IP_PCM0]           = SST_SWM_IN_PCM0,
+       [SST_IP_PCM1]           = SST_SWM_IN_PCM1,
+       [SST_IP_MEDIA0]         = SST_SWM_IN_MEDIA0,
+       [SST_IP_MEDIA1]         = SST_SWM_IN_MEDIA1,
+       [SST_IP_MEDIA2]         = SST_SWM_IN_MEDIA2,
+       [SST_IP_MEDIA3]         = SST_SWM_IN_MEDIA3,
+};
+
+/**
+ * fill_swm_input - fill in the SWM input ids given the register
+ *
+ * The register value is a bit-field inicated which mixer inputs are ON. Use the
+ * lookup table to get the input-id and fill it in the structure.
+ */
+static int fill_swm_input(struct snd_soc_component *cmpnt,
+               struct swm_input_ids *swm_input, unsigned int reg)
+{
+       uint i, is_set, nb_inputs = 0;
+       u16 input_loc_id;
+
+       dev_dbg(cmpnt->dev, "reg: %#x\n", reg);
+       for (i = 0; i < SST_SWM_INPUT_COUNT; i++) {
+               is_set = reg & BIT(i);
+               if (!is_set)
+                       continue;
+
+               input_loc_id = swm_mixer_input_ids[i];
+               SST_FILL_DESTINATION(2, swm_input->input_id,
+                                    input_loc_id, SST_DEFAULT_MODULE_ID);
+               nb_inputs++;
+               swm_input++;
+               dev_dbg(cmpnt->dev, "input id: %#x, nb_inputs: %d\n",
+                               input_loc_id, nb_inputs);
+
+               if (nb_inputs == SST_CMD_SWM_MAX_INPUTS) {
+                       dev_warn(cmpnt->dev, "SET_SWM cmd max inputs reached");
+                       break;
+               }
+       }
+       return nb_inputs;
+}
+
+
+/**
+ * called with lock held
+ */
+static int sst_set_pipe_gain(struct sst_ids *ids,
+                       struct sst_data *drv, int mute)
+{
+       int ret = 0;
+       struct sst_gain_mixer_control *mc;
+       struct sst_gain_value *gv;
+       struct sst_module *gain = NULL;
+
+       list_for_each_entry(gain, &ids->gain_list, node) {
+               struct snd_kcontrol *kctl = gain->kctl;
+
+               dev_dbg(&drv->pdev->dev, "control name=%s\n", kctl->id.name);
+               mc = (void *)kctl->private_value;
+               gv = mc->gain_val;
+
+               ret = sst_send_gain_cmd(drv, gv, mc->task_id,
+                       mc->pipe_id | mc->instance_id, mc->module_id, mute);
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
+
+static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event)
+{
+       struct sst_cmd_set_swm cmd;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+       struct sst_ids *ids = w->priv;
+       bool set_mixer = false;
+       struct soc_mixer_control *mc;
+       int val = 0;
+       int i = 0;
+
+       dev_dbg(cmpnt->dev, "widget = %s\n", w->name);
+       /*
+        * Identify which mixer input is on and send the bitmap of the
+        * inputs as an IPC to the DSP.
+        */
+       for (i = 0; i < w->num_kcontrols; i++) {
+               if (dapm_kcontrol_get_value(w->kcontrols[i])) {
+                       mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
+                       val |= 1 << mc->shift;
+               }
+       }
+       dev_dbg(cmpnt->dev, "val = %#x\n", val);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               set_mixer = true;
+               break;
+       case SND_SOC_DAPM_POST_REG:
+               if (w->power)
+                       set_mixer = true;
+               break;
+       default:
+               set_mixer = false;
+       }
+
+       if (set_mixer == false)
+               return 0;
+
+       if (SND_SOC_DAPM_EVENT_ON(event) ||
+           event == SND_SOC_DAPM_POST_REG)
+               cmd.switch_state = SST_SWM_ON;
+       else
+               cmd.switch_state = SST_SWM_OFF;
+
+       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+       /* MMX_SET_SWM == SBA_SET_SWM */
+       cmd.header.command_id = SBA_SET_SWM;
+
+       SST_FILL_DESTINATION(2, cmd.output_id,
+                            ids->location_id, SST_DEFAULT_MODULE_ID);
+       cmd.nb_inputs = fill_swm_input(cmpnt, &cmd.input[0], val);
+       cmd.header.length = offsetof(struct sst_cmd_set_swm, input)
+                               - sizeof(struct sst_dsp_header)
+                               + (cmd.nb_inputs * sizeof(cmd.input[0]));
+
+       return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
+                             ids->task_id, 0, &cmd,
+                             sizeof(cmd.header) + cmd.header.length);
+}
+
+/* SBA mixers - 16 inputs */
+#define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name)                                                        \
+       static const struct snd_kcontrol_new kctl_name[] = {                                    \
+               SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0),         \
+               SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0),         \
+               SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0),      \
+               SOC_DAPM_SINGLE("media_loop1_in Switch", SND_SOC_NOPM, SST_IP_LOOP1, 1, 0),     \
+               SOC_DAPM_SINGLE("media_loop2_in Switch", SND_SOC_NOPM, SST_IP_LOOP2, 1, 0),     \
+               SOC_DAPM_SINGLE("pcm0_in Switch", SND_SOC_NOPM, SST_IP_PCM0, 1, 0),             \
+               SOC_DAPM_SINGLE("pcm1_in Switch", SND_SOC_NOPM, SST_IP_PCM1, 1, 0),             \
+       }
+
+#define SST_SBA_MIXER_GRAPH_MAP(mix_name)                      \
+       { mix_name, "codec_in0 Switch", "codec_in0" },          \
+       { mix_name, "codec_in1 Switch", "codec_in1" },          \
+       { mix_name, "sprot_loop_in Switch",     "sprot_loop_in" },      \
+       { mix_name, "media_loop1_in Switch",    "media_loop1_in" },     \
+       { mix_name, "media_loop2_in Switch",    "media_loop2_in" },     \
+       { mix_name, "pcm0_in Switch",           "pcm0_in" },            \
+       { mix_name, "pcm1_in Switch",           "pcm1_in" }
+
+#define SST_MMX_DECLARE_MIX_CONTROLS(kctl_name)                                                \
+       static const struct snd_kcontrol_new kctl_name[] = {                            \
+               SOC_DAPM_SINGLE("media0_in Switch", SND_SOC_NOPM, SST_IP_MEDIA0, 1, 0), \
+               SOC_DAPM_SINGLE("media1_in Switch", SND_SOC_NOPM, SST_IP_MEDIA1, 1, 0), \
+               SOC_DAPM_SINGLE("media2_in Switch", SND_SOC_NOPM, SST_IP_MEDIA2, 1, 0), \
+               SOC_DAPM_SINGLE("media3_in Switch", SND_SOC_NOPM, SST_IP_MEDIA3, 1, 0), \
+       }
+
+SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media0_controls);
+SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media1_controls);
+
+/* 18 SBA mixers */
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm1_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls);
+
+/*
+ * sst_handle_vb_timer - Start/Stop the DSP scheduler
+ *
+ * The DSP expects first cmd to be SBA_VB_START, so at first startup send
+ * that.
+ * DSP expects last cmd to be SBA_VB_IDLE, so at last shutdown send that.
+ *
+ * Do refcount internally so that we send command only at first start
+ * and last end. Since SST driver does its own ref count, invoke sst's
+ * power ops always!
+ */
+int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
+{
+       int ret = 0;
+       struct sst_cmd_generic cmd;
+       struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
+       static int timer_usage;
+
+       if (enable)
+               cmd.header.command_id = SBA_VB_START;
+       else
+               cmd.header.command_id = SBA_IDLE;
+       dev_dbg(dai->dev, "enable=%u, usage=%d\n", enable, timer_usage);
+
+       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+       cmd.header.length = 0;
+
+       if (enable) {
+               ret = sst->ops->power(sst->dev, true);
+               if (ret < 0)
+                       return ret;
+       }
+
+       mutex_lock(&drv->lock);
+       if (enable)
+               timer_usage++;
+       else
+               timer_usage--;
+
+       /*
+        * Send the command only if this call is the first enable or last
+        * disable
+        */
+       if ((enable && (timer_usage == 1)) ||
+           (!enable && (timer_usage == 0))) {
+               ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
+                               SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
+                               sizeof(cmd.header) + cmd.header.length);
+               if (ret && enable) {
+                       timer_usage--;
+                       enable  = false;
+               }
+       }
+       mutex_unlock(&drv->lock);
+
+       if (!enable)
+               sst->ops->power(sst->dev, false);
+       return ret;
+}
+
+/**
+ * sst_ssp_config - contains SSP configuration for media UC
+ */
+static const struct sst_ssp_config sst_ssp_configs = {
+       .ssp_id = SSP_CODEC,
+       .bits_per_slot = 24,
+       .slots = 4,
+       .ssp_mode = SSP_MODE_MASTER,
+       .pcm_mode = SSP_PCM_MODE_NETWORK,
+       .duplex = SSP_DUPLEX,
+       .ssp_protocol = SSP_MODE_PCM,
+       .fs_width = 1,
+       .fs_frequency = SSP_FS_48_KHZ,
+       .active_slot_map = 0xF,
+       .start_delay = 0,
+};
+
+int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable)
+{
+       struct sst_cmd_sba_hw_set_ssp cmd;
+       struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
+       const struct sst_ssp_config *config;
+
+       dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);
+
+       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+       cmd.header.command_id = SBA_HW_SET_SSP;
+       cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp)
+                               - sizeof(struct sst_dsp_header);
+
+       config = &sst_ssp_configs;
+       dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id);
+
+       if (enable)
+               cmd.switch_state = SST_SWITCH_ON;
+       else
+               cmd.switch_state = SST_SWITCH_OFF;
+
+       cmd.selection = config->ssp_id;
+       cmd.nb_bits_per_slots = config->bits_per_slot;
+       cmd.nb_slots = config->slots;
+       cmd.mode = config->ssp_mode | (config->pcm_mode << 1);
+       cmd.duplex = config->duplex;
+       cmd.active_tx_slot_map = config->active_slot_map;
+       cmd.active_rx_slot_map = config->active_slot_map;
+       cmd.frame_sync_frequency = config->fs_frequency;
+       cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH;
+       cmd.data_polarity = 1;
+       cmd.frame_sync_width = config->fs_width;
+       cmd.ssp_protocol = config->ssp_protocol;
+       cmd.start_delay = config->start_delay;
+       cmd.reserved1 = cmd.reserved2 = 0xFF;
+
+       return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
+                               SST_TASK_SBA, 0, &cmd,
+                               sizeof(cmd.header) + cmd.header.length);
+}
+
+static int sst_set_be_modules(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *k, int event)
+{
+       int ret = 0;
+       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+       struct sst_data *drv = snd_soc_component_get_drvdata(c);
+
+       dev_dbg(c->dev, "Enter: widget=%s\n", w->name);
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = sst_send_slot_map(drv);
+               if (ret)
+                       return ret;
+               ret = sst_send_pipe_module_params(w, k);
+       }
+       return ret;
+}
+
+static int sst_set_media_path(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *k, int event)
+{
+       int ret = 0;
+       struct sst_cmd_set_media_path cmd;
+       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+       struct sst_data *drv = snd_soc_component_get_drvdata(c);
+       struct sst_ids *ids = w->priv;
+
+       dev_dbg(c->dev, "widget=%s\n", w->name);
+       dev_dbg(c->dev, "task=%u, location=%#x\n",
+                               ids->task_id, ids->location_id);
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               cmd.switch_state = SST_PATH_ON;
+       else
+               cmd.switch_state = SST_PATH_OFF;
+
+       SST_FILL_DESTINATION(2, cmd.header.dst,
+                            ids->location_id, SST_DEFAULT_MODULE_ID);
+
+       /* MMX_SET_MEDIA_PATH == SBA_SET_MEDIA_PATH */
+       cmd.header.command_id = MMX_SET_MEDIA_PATH;
+       cmd.header.length = sizeof(struct sst_cmd_set_media_path)
+                               - sizeof(struct sst_dsp_header);
+
+       ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
+                             ids->task_id, 0, &cmd,
+                             sizeof(cmd.header) + cmd.header.length);
+       if (ret)
+               return ret;
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               ret = sst_send_pipe_module_params(w, k);
+       return ret;
+}
+
+static int sst_set_media_loop(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event)
+{
+       int ret = 0;
+       struct sst_cmd_sba_set_media_loop_map cmd;
+       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+       struct sst_data *drv = snd_soc_component_get_drvdata(c);
+       struct sst_ids *ids = w->priv;
+
+       dev_dbg(c->dev, "Enter:widget=%s\n", w->name);
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               cmd.switch_state = SST_SWITCH_ON;
+       else
+               cmd.switch_state = SST_SWITCH_OFF;
+
+       SST_FILL_DESTINATION(2, cmd.header.dst,
+                            ids->location_id, SST_DEFAULT_MODULE_ID);
+
+       cmd.header.command_id = SBA_SET_MEDIA_LOOP_MAP;
+       cmd.header.length = sizeof(struct sst_cmd_sba_set_media_loop_map)
+                                - sizeof(struct sst_dsp_header);
+       cmd.param.part.cfg.rate = 2; /* 48khz */
+
+       cmd.param.part.cfg.format = ids->format; /* stereo/Mono */
+       cmd.param.part.cfg.s_length = 1; /* 24bit left justified */
+       cmd.map = 0; /* Algo sequence: Gain - DRP - FIR - IIR */
+
+       ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
+                             SST_TASK_SBA, 0, &cmd,
+                             sizeof(cmd.header) + cmd.header.length);
+       if (ret)
+               return ret;
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               ret = sst_send_pipe_module_params(w, k);
+       return ret;
+}
+
+static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
+       SST_AIF_IN("codec_in0", sst_set_be_modules),
+       SST_AIF_IN("codec_in1", sst_set_be_modules),
+       SST_AIF_OUT("codec_out0", sst_set_be_modules),
+       SST_AIF_OUT("codec_out1", sst_set_be_modules),
+
+       /* Media Paths */
+       /* MediaX IN paths are set via ALLOC, so no SET_MEDIA_PATH command */
+       SST_PATH_INPUT("media0_in", SST_TASK_MMX, SST_SWM_IN_MEDIA0, sst_generic_modules_event),
+       SST_PATH_INPUT("media1_in", SST_TASK_MMX, SST_SWM_IN_MEDIA1, NULL),
+       SST_PATH_INPUT("media2_in", SST_TASK_MMX, SST_SWM_IN_MEDIA2, sst_set_media_path),
+       SST_PATH_INPUT("media3_in", SST_TASK_MMX, SST_SWM_IN_MEDIA3, NULL),
+       SST_PATH_OUTPUT("media0_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA0, sst_set_media_path),
+       SST_PATH_OUTPUT("media1_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA1, sst_set_media_path),
+
+       /* SBA PCM Paths */
+       SST_PATH_INPUT("pcm0_in", SST_TASK_SBA, SST_SWM_IN_PCM0, sst_set_media_path),
+       SST_PATH_INPUT("pcm1_in", SST_TASK_SBA, SST_SWM_IN_PCM1, sst_set_media_path),
+       SST_PATH_OUTPUT("pcm0_out", SST_TASK_SBA, SST_SWM_OUT_PCM0, sst_set_media_path),
+       SST_PATH_OUTPUT("pcm1_out", SST_TASK_SBA, SST_SWM_OUT_PCM1, sst_set_media_path),
+       SST_PATH_OUTPUT("pcm2_out", SST_TASK_SBA, SST_SWM_OUT_PCM2, sst_set_media_path),
+
+       /* SBA Loops */
+       SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL),
+       SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL),
+       SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL),
+       SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop),
+       SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop),
+       SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop),
+
+       /* Media Mixers */
+       SST_SWM_MIXER("media0_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA0,
+                     sst_mix_media0_controls, sst_swm_mixer_event),
+       SST_SWM_MIXER("media1_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA1,
+                     sst_mix_media1_controls, sst_swm_mixer_event),
+
+       /* SBA PCM mixers */
+       SST_SWM_MIXER("pcm0_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM0,
+                     sst_mix_pcm0_controls, sst_swm_mixer_event),
+       SST_SWM_MIXER("pcm1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM1,
+                     sst_mix_pcm1_controls, sst_swm_mixer_event),
+       SST_SWM_MIXER("pcm2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM2,
+                     sst_mix_pcm2_controls, sst_swm_mixer_event),
+
+       /* SBA Loop mixers */
+       SST_SWM_MIXER("sprot_loop_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP,
+                     sst_mix_sprot_l0_controls, sst_swm_mixer_event),
+       SST_SWM_MIXER("media_loop1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1,
+                     sst_mix_media_l1_controls, sst_swm_mixer_event),
+       SST_SWM_MIXER("media_loop2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2,
+                     sst_mix_media_l2_controls, sst_swm_mixer_event),
+
+       /* SBA Backend mixers */
+       SST_SWM_MIXER("codec_out0 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC0,
+                     sst_mix_codec0_controls, sst_swm_mixer_event),
+       SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1,
+                     sst_mix_codec1_controls, sst_swm_mixer_event),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       {"media0_in", NULL, "Compress Playback"},
+       {"media1_in", NULL, "Headset Playback"},
+       {"media2_in", NULL, "pcm0_out"},
+
+       {"media0_out mix 0", "media0_in Switch", "media0_in"},
+       {"media0_out mix 0", "media1_in Switch", "media1_in"},
+       {"media0_out mix 0", "media2_in Switch", "media2_in"},
+       {"media0_out mix 0", "media3_in Switch", "media3_in"},
+       {"media1_out mix 0", "media0_in Switch", "media0_in"},
+       {"media1_out mix 0", "media1_in Switch", "media1_in"},
+       {"media1_out mix 0", "media2_in Switch", "media2_in"},
+       {"media1_out mix 0", "media3_in Switch", "media3_in"},
+
+       {"media0_out", NULL, "media0_out mix 0"},
+       {"media1_out", NULL, "media1_out mix 0"},
+       {"pcm0_in", NULL, "media0_out"},
+       {"pcm1_in", NULL, "media1_out"},
+
+       {"Headset Capture", NULL, "pcm1_out"},
+       {"Headset Capture", NULL, "pcm2_out"},
+       {"pcm0_out", NULL, "pcm0_out mix 0"},
+       SST_SBA_MIXER_GRAPH_MAP("pcm0_out mix 0"),
+       {"pcm1_out", NULL, "pcm1_out mix 0"},
+       SST_SBA_MIXER_GRAPH_MAP("pcm1_out mix 0"),
+       {"pcm2_out", NULL, "pcm2_out mix 0"},
+       SST_SBA_MIXER_GRAPH_MAP("pcm2_out mix 0"),
+
+       {"media_loop1_in", NULL, "media_loop1_out"},
+       {"media_loop1_out", NULL, "media_loop1_out mix 0"},
+       SST_SBA_MIXER_GRAPH_MAP("media_loop1_out mix 0"),
+       {"media_loop2_in", NULL, "media_loop2_out"},
+       {"media_loop2_out", NULL, "media_loop2_out mix 0"},
+       SST_SBA_MIXER_GRAPH_MAP("media_loop2_out mix 0"),
+       {"sprot_loop_in", NULL, "sprot_loop_out"},
+       {"sprot_loop_out", NULL, "sprot_loop_out mix 0"},
+       SST_SBA_MIXER_GRAPH_MAP("sprot_loop_out mix 0"),
+
+       {"codec_out0", NULL, "codec_out0 mix 0"},
+       SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"),
+       {"codec_out1", NULL, "codec_out1 mix 0"},
+       SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"),
+
+};
+static const char * const slot_names[] = {
+       "none",
+       "slot 0", "slot 1", "slot 2", "slot 3",
+       "slot 4", "slot 5", "slot 6", "slot 7", /* not supported by FW */
+};
+
+static const char * const channel_names[] = {
+       "none",
+       "codec_out0_0", "codec_out0_1", "codec_out1_0", "codec_out1_1",
+       "codec_out2_0", "codec_out2_1", "codec_out3_0", "codec_out3_1", /* not supported by FW */
+};
+
+#define SST_INTERLEAVER(xpname, slot_name, slotno) \
+       SST_SSP_SLOT_CTL(xpname, "tx interleaver", slot_name, slotno, true, \
+                        channel_names, sst_slot_get, sst_slot_put)
+
+#define SST_DEINTERLEAVER(xpname, channel_name, channel_no) \
+       SST_SSP_SLOT_CTL(xpname, "rx deinterleaver", channel_name, channel_no, false, \
+                        slot_names, sst_slot_get, sst_slot_put)
+
+static const struct snd_kcontrol_new sst_slot_controls[] = {
+       SST_INTERLEAVER("codec_out", "slot 0", 0),
+       SST_INTERLEAVER("codec_out", "slot 1", 1),
+       SST_INTERLEAVER("codec_out", "slot 2", 2),
+       SST_INTERLEAVER("codec_out", "slot 3", 3),
+       SST_DEINTERLEAVER("codec_in", "codec_in0_0", 0),
+       SST_DEINTERLEAVER("codec_in", "codec_in0_1", 1),
+       SST_DEINTERLEAVER("codec_in", "codec_in1_0", 2),
+       SST_DEINTERLEAVER("codec_in", "codec_in1_1", 3),
+};
+
+/* Gain helper with min/max set */
+#define SST_GAIN(name, path_id, task_id, instance, gain_var)                           \
+       SST_GAIN_KCONTROLS(name, "Gain", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE,        \
+               SST_GAIN_TC_MIN, SST_GAIN_TC_MAX,                                       \
+               sst_gain_get, sst_gain_put,                                             \
+               SST_MODULE_ID_GAIN_CELL, path_id, instance, task_id,                    \
+               sst_gain_tlv_common, gain_var)
+
+#define SST_VOLUME(name, path_id, task_id, instance, gain_var)                         \
+       SST_GAIN_KCONTROLS(name, "Volume", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE,      \
+               SST_GAIN_TC_MIN, SST_GAIN_TC_MAX,                                       \
+               sst_gain_get, sst_gain_put,                                             \
+               SST_MODULE_ID_VOLUME, path_id, instance, task_id,                       \
+               sst_gain_tlv_common, gain_var)
+
+static struct sst_gain_value sst_gains[];
+
+static const struct snd_kcontrol_new sst_gain_controls[] = {
+       SST_GAIN("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[0]),
+       SST_GAIN("media1_in", SST_PATH_INDEX_MEDIA1_IN, SST_TASK_MMX, 0, &sst_gains[1]),
+       SST_GAIN("media2_in", SST_PATH_INDEX_MEDIA2_IN, SST_TASK_MMX, 0, &sst_gains[2]),
+       SST_GAIN("media3_in", SST_PATH_INDEX_MEDIA3_IN, SST_TASK_MMX, 0, &sst_gains[3]),
+
+       SST_GAIN("pcm0_in", SST_PATH_INDEX_PCM0_IN, SST_TASK_SBA, 0, &sst_gains[4]),
+       SST_GAIN("pcm1_in", SST_PATH_INDEX_PCM1_IN, SST_TASK_SBA, 0, &sst_gains[5]),
+       SST_GAIN("pcm1_out", SST_PATH_INDEX_PCM1_OUT, SST_TASK_SBA, 0, &sst_gains[6]),
+       SST_GAIN("pcm2_out", SST_PATH_INDEX_PCM2_OUT, SST_TASK_SBA, 0, &sst_gains[7]),
+
+       SST_GAIN("codec_in0", SST_PATH_INDEX_CODEC_IN0, SST_TASK_SBA, 0, &sst_gains[8]),
+       SST_GAIN("codec_in1", SST_PATH_INDEX_CODEC_IN1, SST_TASK_SBA, 0, &sst_gains[9]),
+       SST_GAIN("codec_out0", SST_PATH_INDEX_CODEC_OUT0, SST_TASK_SBA, 0, &sst_gains[10]),
+       SST_GAIN("codec_out1", SST_PATH_INDEX_CODEC_OUT1, SST_TASK_SBA, 0, &sst_gains[11]),
+       SST_GAIN("media_loop1_out", SST_PATH_INDEX_MEDIA_LOOP1_OUT, SST_TASK_SBA, 0, &sst_gains[12]),
+       SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]),
+       SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]),
+       SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]),
+};
+
+#define SST_GAIN_NUM_CONTROLS 3
+/* the SST_GAIN macro above will create three alsa controls for each
+ * instance invoked, gain, mute and ramp duration, which use the same gain
+ * cell sst_gain to keep track of data
+ * To calculate number of gain cell instances we need to device by 3 in
+ * below caulcation for gain cell memory.
+ * This gets rid of static number and issues while adding new controls
+ */
+static struct sst_gain_value sst_gains[ARRAY_SIZE(sst_gain_controls)/SST_GAIN_NUM_CONTROLS];
+
+static const struct snd_kcontrol_new sst_algo_controls[] = {
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
+                SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+               SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+       SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT,
+               SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO),
+       SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+               SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+               SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+
+};
+
+static int sst_algo_control_init(struct device *dev)
+{
+       int i = 0;
+       struct sst_algo_control *bc;
+       /*allocate space to cache the algo parameters in the driver*/
+       for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) {
+               bc = (struct sst_algo_control *)sst_algo_controls[i].private_value;
+               bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL);
+               if (bc->params == NULL)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+static bool is_sst_dapm_widget(struct snd_soc_dapm_widget *w)
+{
+       switch (w->id) {
+       case snd_soc_dapm_pga:
+       case snd_soc_dapm_aif_in:
+       case snd_soc_dapm_aif_out:
+       case snd_soc_dapm_input:
+       case snd_soc_dapm_output:
+       case snd_soc_dapm_mixer:
+               return true;
+       default:
+               return false;
+       }
+}
+
+/**
+ * sst_send_pipe_gains - send gains for the front-end DAIs
+ *
+ * The gains in the pipes connected to the front-ends are muted/unmuted
+ * automatically via the digital_mute() DAPM callback. This function sends the
+ * gains for the front-end pipes.
+ */
+int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
+{
+       struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
+       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_path *p = NULL;
+
+       dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dev_dbg(dai->dev, "Stream name=%s\n",
+                               dai->playback_widget->name);
+               w = dai->playback_widget;
+               list_for_each_entry(p, &w->sinks, list_source) {
+                       if (p->connected && !p->connected(w, p->sink))
+                               continue;
+
+                       if (p->connect && p->sink->power &&
+                                       is_sst_dapm_widget(p->sink)) {
+                               struct sst_ids *ids = p->sink->priv;
+
+                               dev_dbg(dai->dev, "send gains for widget=%s\n",
+                                               p->sink->name);
+                               mutex_lock(&drv->lock);
+                               sst_set_pipe_gain(ids, drv, mute);
+                               mutex_unlock(&drv->lock);
+                       }
+               }
+       } else {
+               dev_dbg(dai->dev, "Stream name=%s\n",
+                               dai->capture_widget->name);
+               w = dai->capture_widget;
+               list_for_each_entry(p, &w->sources, list_sink) {
+                       if (p->connected && !p->connected(w, p->sink))
+                               continue;
+
+                       if (p->connect &&  p->source->power &&
+                                       is_sst_dapm_widget(p->source)) {
+                               struct sst_ids *ids = p->source->priv;
+
+                               dev_dbg(dai->dev, "send gain for widget=%s\n",
+                                               p->source->name);
+                               mutex_lock(&drv->lock);
+                               sst_set_pipe_gain(ids, drv, mute);
+                               mutex_unlock(&drv->lock);
+                       }
+               }
+       }
+       return 0;
+}
+
+/**
+ * sst_fill_module_list - populate the list of modules/gains for a pipe
+ *
+ *
+ * Fills the widget pointer in the kcontrol private data, and also fills the
+ * kcontrol pointer in the widget private data.
+ *
+ * Widget pointer is used to send the algo/gain in the .put() handler if the
+ * widget is powerd on.
+ *
+ * Kcontrol pointer is used to send the algo/gain in the widget power ON/OFF
+ * event handler. Each widget (pipe) has multiple algos stored in the algo_list.
+ */
+static int sst_fill_module_list(struct snd_kcontrol *kctl,
+        struct snd_soc_dapm_widget *w, int type)
+{
+       struct sst_module *module = NULL;
+       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+       struct sst_ids *ids = w->priv;
+       int ret = 0;
+
+       module = devm_kzalloc(c->dev, sizeof(*module), GFP_KERNEL);
+       if (!module)
+               return -ENOMEM;
+
+       if (type == SST_MODULE_GAIN) {
+               struct sst_gain_mixer_control *mc = (void *)kctl->private_value;
+
+               mc->w = w;
+               module->kctl = kctl;
+               list_add_tail(&module->node, &ids->gain_list);
+       } else if (type == SST_MODULE_ALGO) {
+               struct sst_algo_control *bc = (void *)kctl->private_value;
+
+               bc->w = w;
+               module->kctl = kctl;
+               list_add_tail(&module->node, &ids->algo_list);
+       } else {
+               dev_err(c->dev, "invoked for unknown type %d module %s",
+                               type, kctl->id.name);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+/**
+ * sst_fill_widget_module_info - fill list of gains/algos for the pipe
+ * @widget:    pipe modelled as a DAPM widget
+ *
+ * Fill the list of gains/algos for the widget by looking at all the card
+ * controls and comparing the name of the widget with the first part of control
+ * name. First part of control name contains the pipe name (widget name).
+ */
+static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w,
+       struct snd_soc_platform *platform)
+{
+       struct snd_kcontrol *kctl;
+       int index, ret = 0;
+       struct snd_card *card = platform->component.card->snd_card;
+       char *idx;
+
+       down_read(&card->controls_rwsem);
+
+       list_for_each_entry(kctl, &card->controls, list) {
+               idx = strstr(kctl->id.name, " ");
+               if (idx == NULL)
+                       continue;
+               index  = strlen(kctl->id.name) - strlen(idx);
+
+               if (strstr(kctl->id.name, "Volume") &&
+                   !strncmp(kctl->id.name, w->name, index))
+                       ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN);
+
+               else if (strstr(kctl->id.name, "params") &&
+                        !strncmp(kctl->id.name, w->name, index))
+                       ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO);
+
+               else if (strstr(kctl->id.name, "Switch") &&
+                        !strncmp(kctl->id.name, w->name, index) &&
+                        strstr(kctl->id.name, "Gain")) {
+                       struct sst_gain_mixer_control *mc =
+                                               (void *)kctl->private_value;
+
+                       mc->w = w;
+
+               } else if (strstr(kctl->id.name, "interleaver") &&
+                        !strncmp(kctl->id.name, w->name, index)) {
+                       struct sst_enum *e = (void *)kctl->private_value;
+
+                       e->w = w;
+
+               } else if (strstr(kctl->id.name, "deinterleaver") &&
+                        !strncmp(kctl->id.name, w->name, index)) {
+
+                       struct sst_enum *e = (void *)kctl->private_value;
+
+                       e->w = w;
+               }
+
+               if (ret < 0) {
+                       up_read(&card->controls_rwsem);
+                       return ret;
+               }
+       }
+
+       up_read(&card->controls_rwsem);
+       return 0;
+}
+
+/**
+ * sst_fill_linked_widgets - fill the parent pointer for the linked widget
+ */
+static void sst_fill_linked_widgets(struct snd_soc_platform *platform,
+                                               struct sst_ids *ids)
+{
+       struct snd_soc_dapm_widget *w;
+       unsigned int len = strlen(ids->parent_wname);
+
+       list_for_each_entry(w, &platform->component.card->widgets, list) {
+               if (!strncmp(ids->parent_wname, w->name, len)) {
+                       ids->parent_w = w;
+                       break;
+               }
+       }
+}
+
+/**
+ * sst_map_modules_to_pipe - fill algo/gains list for all pipes
+ */
+static int sst_map_modules_to_pipe(struct snd_soc_platform *platform)
+{
+       struct snd_soc_dapm_widget *w;
+       int ret = 0;
+
+       list_for_each_entry(w, &platform->component.card->widgets, list) {
+               if (is_sst_dapm_widget(w) && (w->priv)) {
+                       struct sst_ids *ids = w->priv;
+
+                       dev_dbg(platform->dev, "widget type=%d name=%s\n",
+                                       w->id, w->name);
+                       INIT_LIST_HEAD(&ids->algo_list);
+                       INIT_LIST_HEAD(&ids->gain_list);
+                       ret = sst_fill_widget_module_info(w, platform);
+
+                       if (ret < 0)
+                               return ret;
+
+                       /* fill linked widgets */
+                       if (ids->parent_wname !=  NULL)
+                               sst_fill_linked_widgets(platform, ids);
+               }
+       }
+       return 0;
+}
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
+{
+       int i, ret = 0;
+       struct snd_soc_dapm_context *dapm =
+                       snd_soc_component_get_dapm(&platform->component);
+       struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
+       unsigned int gains = ARRAY_SIZE(sst_gain_controls)/3;
+
+       drv->byte_stream = devm_kzalloc(platform->dev,
+                                       SST_MAX_BIN_BYTES, GFP_KERNEL);
+       if (!drv->byte_stream)
+               return -ENOMEM;
+
+       snd_soc_dapm_new_controls(dapm, sst_dapm_widgets,
+                       ARRAY_SIZE(sst_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon,
+                       ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_widgets(dapm->card);
+
+       for (i = 0; i < gains; i++) {
+               sst_gains[i].mute = SST_GAIN_MUTE_DEFAULT;
+               sst_gains[i].l_gain = SST_GAIN_VOLUME_DEFAULT;
+               sst_gains[i].r_gain = SST_GAIN_VOLUME_DEFAULT;
+               sst_gains[i].ramp_duration = SST_GAIN_RAMP_DURATION_DEFAULT;
+       }
+
+       ret = snd_soc_add_platform_controls(platform, sst_gain_controls,
+                       ARRAY_SIZE(sst_gain_controls));
+       if (ret)
+               return ret;
+
+       /* Initialize algo control params */
+       ret = sst_algo_control_init(platform->dev);
+       if (ret)
+               return ret;
+       ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
+                       ARRAY_SIZE(sst_algo_controls));
+       if (ret)
+               return ret;
+
+       ret = snd_soc_add_platform_controls(platform, sst_slot_controls,
+                       ARRAY_SIZE(sst_slot_controls));
+       if (ret)
+               return ret;
+
+       ret = sst_map_modules_to_pipe(platform);
+
+       return ret;
+}
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h
new file mode 100644 (file)
index 0000000..daecc58
--- /dev/null
@@ -0,0 +1,870 @@
+/*
+ *  sst-atom-controls.h - Intel MID Platform driver header file
+ *
+ *  Copyright (C) 2013-14 Intel Corp
+ *  Author: Ramesh Babu <ramesh.babu.koul@intel.com>
+ *     Omair M Abdullah <omair.m.abdullah@intel.com>
+ *     Samreen Nilofer <samreen.nilofer@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#ifndef __SST_ATOM_CONTROLS_H__
+#define __SST_ATOM_CONTROLS_H__
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+enum {
+       MERR_DPCM_AUDIO = 0,
+       MERR_DPCM_COMPR,
+};
+
+/* define a bit for each mixer input */
+#define SST_MIX_IP(x)          (x)
+
+#define SST_IP_CODEC0          SST_MIX_IP(2)
+#define SST_IP_CODEC1          SST_MIX_IP(3)
+#define SST_IP_LOOP0           SST_MIX_IP(4)
+#define SST_IP_LOOP1           SST_MIX_IP(5)
+#define SST_IP_LOOP2           SST_MIX_IP(6)
+#define SST_IP_PROBE           SST_MIX_IP(7)
+#define SST_IP_VOIP            SST_MIX_IP(12)
+#define SST_IP_PCM0            SST_MIX_IP(13)
+#define SST_IP_PCM1            SST_MIX_IP(14)
+#define SST_IP_MEDIA0          SST_MIX_IP(17)
+#define SST_IP_MEDIA1          SST_MIX_IP(18)
+#define SST_IP_MEDIA2          SST_MIX_IP(19)
+#define SST_IP_MEDIA3          SST_MIX_IP(20)
+
+#define SST_IP_LAST            SST_IP_MEDIA3
+
+#define SST_SWM_INPUT_COUNT    (SST_IP_LAST + 1)
+#define SST_CMD_SWM_MAX_INPUTS 6
+
+#define SST_PATH_ID_SHIFT      8
+#define SST_DEFAULT_LOCATION_ID        0xFFFF
+#define SST_DEFAULT_CELL_NBR   0xFF
+#define SST_DEFAULT_MODULE_ID  0xFFFF
+
+/*
+ * Audio DSP Path Ids. Specified by the audio DSP FW
+ */
+enum sst_path_index {
+       SST_PATH_INDEX_CODEC_OUT0               = (0x02 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_CODEC_OUT1               = (0x03 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_SPROT_LOOP_OUT           = (0x04 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA_LOOP1_OUT          = (0x05 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA_LOOP2_OUT          = (0x06 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_VOIP_OUT                 = (0x0C << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_PCM0_OUT                 = (0x0D << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_PCM1_OUT                 = (0x0E << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_PCM2_OUT                 = (0x0F << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_MEDIA0_OUT               = (0x12 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA1_OUT               = (0x13 << SST_PATH_ID_SHIFT),
+
+
+       /* Start of input paths */
+       SST_PATH_INDEX_CODEC_IN0                = (0x82 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_CODEC_IN1                = (0x83 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_SPROT_LOOP_IN            = (0x84 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA_LOOP1_IN           = (0x85 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA_LOOP2_IN           = (0x86 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_VOIP_IN                  = (0x8C << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_PCM0_IN                  = (0x8D << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_PCM1_IN                  = (0x8E << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_MEDIA0_IN                = (0x8F << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA1_IN                = (0x90 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA2_IN                = (0x91 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_MEDIA3_IN                = (0x9C << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_RESERVED                 = (0xFF << SST_PATH_ID_SHIFT),
+};
+
+/*
+ * path IDs
+ */
+enum sst_swm_inputs {
+       SST_SWM_IN_CODEC0       = (SST_PATH_INDEX_CODEC_IN0       | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_CODEC1       = (SST_PATH_INDEX_CODEC_IN1       | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_SPROT_LOOP   = (SST_PATH_INDEX_SPROT_LOOP_IN   | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_MEDIA_LOOP1  = (SST_PATH_INDEX_MEDIA_LOOP1_IN  | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_MEDIA_LOOP2  = (SST_PATH_INDEX_MEDIA_LOOP2_IN  | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_VOIP         = (SST_PATH_INDEX_VOIP_IN         | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_PCM0         = (SST_PATH_INDEX_PCM0_IN         | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_PCM1         = (SST_PATH_INDEX_PCM1_IN         | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_MEDIA0       = (SST_PATH_INDEX_MEDIA0_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_IN_MEDIA1       = (SST_PATH_INDEX_MEDIA1_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_IN_MEDIA2       = (SST_PATH_INDEX_MEDIA2_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_IN_MEDIA3       = (SST_PATH_INDEX_MEDIA3_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_IN_END          = (SST_PATH_INDEX_RESERVED        | SST_DEFAULT_CELL_NBR)
+};
+
+/*
+ * path IDs
+ */
+enum sst_swm_outputs {
+       SST_SWM_OUT_CODEC0      = (SST_PATH_INDEX_CODEC_OUT0      | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_CODEC1      = (SST_PATH_INDEX_CODEC_OUT1      | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_SPROT_LOOP  = (SST_PATH_INDEX_SPROT_LOOP_OUT  | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_VOIP        = (SST_PATH_INDEX_VOIP_OUT        | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_PCM0        = (SST_PATH_INDEX_PCM0_OUT        | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_PCM1        = (SST_PATH_INDEX_PCM1_OUT        | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_PCM2        = (SST_PATH_INDEX_PCM2_OUT        | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_MEDIA0      = (SST_PATH_INDEX_MEDIA0_OUT      | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_OUT_MEDIA1      = (SST_PATH_INDEX_MEDIA1_OUT      | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_OUT_END         = (SST_PATH_INDEX_RESERVED        | SST_DEFAULT_CELL_NBR),
+};
+
+enum sst_ipc_msg {
+       SST_IPC_IA_CMD = 1,
+       SST_IPC_IA_SET_PARAMS,
+       SST_IPC_IA_GET_PARAMS,
+};
+
+enum sst_cmd_type {
+       SST_CMD_BYTES_SET = 1,
+       SST_CMD_BYTES_GET = 2,
+};
+
+enum sst_task {
+       SST_TASK_SBA = 1,
+       SST_TASK_MMX = 3,
+};
+
+enum sst_type {
+       SST_TYPE_CMD = 1,
+       SST_TYPE_PARAMS,
+};
+
+enum sst_flag {
+       SST_FLAG_BLOCKED = 1,
+       SST_FLAG_NONBLOCK,
+};
+
+/*
+ * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command
+ */
+enum sst_gain_index {
+       /* GAIN IDs for SB task start here */
+       SST_GAIN_INDEX_CODEC_OUT0,
+       SST_GAIN_INDEX_CODEC_OUT1,
+       SST_GAIN_INDEX_CODEC_IN0,
+       SST_GAIN_INDEX_CODEC_IN1,
+
+       SST_GAIN_INDEX_SPROT_LOOP_OUT,
+       SST_GAIN_INDEX_MEDIA_LOOP1_OUT,
+       SST_GAIN_INDEX_MEDIA_LOOP2_OUT,
+
+       SST_GAIN_INDEX_PCM0_IN_LEFT,
+       SST_GAIN_INDEX_PCM0_IN_RIGHT,
+
+       SST_GAIN_INDEX_PCM1_OUT_LEFT,
+       SST_GAIN_INDEX_PCM1_OUT_RIGHT,
+       SST_GAIN_INDEX_PCM1_IN_LEFT,
+       SST_GAIN_INDEX_PCM1_IN_RIGHT,
+       SST_GAIN_INDEX_PCM2_OUT_LEFT,
+
+       SST_GAIN_INDEX_PCM2_OUT_RIGHT,
+       SST_GAIN_INDEX_VOIP_OUT,
+       SST_GAIN_INDEX_VOIP_IN,
+
+       /* Gain IDs for MMX task start here */
+       SST_GAIN_INDEX_MEDIA0_IN_LEFT,
+       SST_GAIN_INDEX_MEDIA0_IN_RIGHT,
+       SST_GAIN_INDEX_MEDIA1_IN_LEFT,
+       SST_GAIN_INDEX_MEDIA1_IN_RIGHT,
+
+       SST_GAIN_INDEX_MEDIA2_IN_LEFT,
+       SST_GAIN_INDEX_MEDIA2_IN_RIGHT,
+
+       SST_GAIN_INDEX_GAIN_END
+};
+
+/*
+ * Audio DSP module IDs specified by FW spec
+ * TODO: Update with all modules
+ */
+enum sst_module_id {
+       SST_MODULE_ID_PCM                 = 0x0001,
+       SST_MODULE_ID_MP3                 = 0x0002,
+       SST_MODULE_ID_MP24                = 0x0003,
+       SST_MODULE_ID_AAC                 = 0x0004,
+       SST_MODULE_ID_AACP                = 0x0005,
+       SST_MODULE_ID_EAACP               = 0x0006,
+       SST_MODULE_ID_WMA9                = 0x0007,
+       SST_MODULE_ID_WMA10               = 0x0008,
+       SST_MODULE_ID_WMA10P              = 0x0009,
+       SST_MODULE_ID_RA                  = 0x000A,
+       SST_MODULE_ID_DDAC3               = 0x000B,
+       SST_MODULE_ID_TRUE_HD             = 0x000C,
+       SST_MODULE_ID_HD_PLUS             = 0x000D,
+
+       SST_MODULE_ID_SRC                 = 0x0064,
+       SST_MODULE_ID_DOWNMIX             = 0x0066,
+       SST_MODULE_ID_GAIN_CELL           = 0x0067,
+       SST_MODULE_ID_SPROT               = 0x006D,
+       SST_MODULE_ID_BASS_BOOST          = 0x006E,
+       SST_MODULE_ID_STEREO_WDNG         = 0x006F,
+       SST_MODULE_ID_AV_REMOVAL          = 0x0070,
+       SST_MODULE_ID_MIC_EQ              = 0x0071,
+       SST_MODULE_ID_SPL                 = 0x0072,
+       SST_MODULE_ID_ALGO_VTSV           = 0x0073,
+       SST_MODULE_ID_NR                  = 0x0076,
+       SST_MODULE_ID_BWX                 = 0x0077,
+       SST_MODULE_ID_DRP                 = 0x0078,
+       SST_MODULE_ID_MDRP                = 0x0079,
+
+       SST_MODULE_ID_ANA                 = 0x007A,
+       SST_MODULE_ID_AEC                 = 0x007B,
+       SST_MODULE_ID_NR_SNS              = 0x007C,
+       SST_MODULE_ID_SER                 = 0x007D,
+       SST_MODULE_ID_AGC                 = 0x007E,
+
+       SST_MODULE_ID_CNI                 = 0x007F,
+       SST_MODULE_ID_CONTEXT_ALGO_AWARE  = 0x0080,
+       SST_MODULE_ID_FIR_24              = 0x0081,
+       SST_MODULE_ID_IIR_24              = 0x0082,
+
+       SST_MODULE_ID_ASRC                = 0x0083,
+       SST_MODULE_ID_TONE_GEN            = 0x0084,
+       SST_MODULE_ID_BMF                 = 0x0086,
+       SST_MODULE_ID_EDL                 = 0x0087,
+       SST_MODULE_ID_GLC                 = 0x0088,
+
+       SST_MODULE_ID_FIR_16              = 0x0089,
+       SST_MODULE_ID_IIR_16              = 0x008A,
+       SST_MODULE_ID_DNR                 = 0x008B,
+
+       SST_MODULE_ID_VIRTUALIZER         = 0x008C,
+       SST_MODULE_ID_VISUALIZATION       = 0x008D,
+       SST_MODULE_ID_LOUDNESS_OPTIMIZER  = 0x008E,
+       SST_MODULE_ID_REVERBERATION       = 0x008F,
+
+       SST_MODULE_ID_CNI_TX              = 0x0090,
+       SST_MODULE_ID_REF_LINE            = 0x0091,
+       SST_MODULE_ID_VOLUME              = 0x0092,
+       SST_MODULE_ID_FILT_DCR            = 0x0094,
+       SST_MODULE_ID_SLV                 = 0x009A,
+       SST_MODULE_ID_NLF                 = 0x009B,
+       SST_MODULE_ID_TNR                 = 0x009C,
+       SST_MODULE_ID_WNR                 = 0x009D,
+
+       SST_MODULE_ID_LOG                 = 0xFF00,
+
+       SST_MODULE_ID_TASK                = 0xFFFF,
+};
+
+enum sst_cmd {
+       SBA_IDLE                = 14,
+       SBA_VB_SET_SPEECH_PATH  = 26,
+       MMX_SET_GAIN            = 33,
+       SBA_VB_SET_GAIN         = 33,
+       FBA_VB_RX_CNI           = 35,
+       MMX_SET_GAIN_TIMECONST  = 36,
+       SBA_VB_SET_TIMECONST    = 36,
+       SBA_VB_START            = 85,
+       SBA_SET_SWM             = 114,
+       SBA_SET_MDRP            = 116,
+       SBA_HW_SET_SSP          = 117,
+       SBA_SET_MEDIA_LOOP_MAP  = 118,
+       SBA_SET_MEDIA_PATH      = 119,
+       MMX_SET_MEDIA_PATH      = 119,
+       SBA_VB_LPRO             = 126,
+       SBA_VB_SET_FIR          = 128,
+       SBA_VB_SET_IIR          = 129,
+       SBA_SET_SSP_SLOT_MAP    = 130,
+};
+
+enum sst_dsp_switch {
+       SST_SWITCH_OFF = 0,
+       SST_SWITCH_ON = 3,
+};
+
+enum sst_path_switch {
+       SST_PATH_OFF = 0,
+       SST_PATH_ON = 1,
+};
+
+enum sst_swm_state {
+       SST_SWM_OFF = 0,
+       SST_SWM_ON = 3,
+};
+
+#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id)          do {    \
+               dst.location_id.p.cell_nbr_idx = (cell_idx);            \
+               dst.location_id.p.path_id = (pipe_id);                  \
+       } while (0)
+#define SST_FILL_LOCATION_ID(dst, loc_id)                              (\
+       dst.location_id.f = (loc_id))
+#define SST_FILL_MODULE_ID(dst, mod_id)                                        (\
+       dst.module_id = (mod_id))
+
+#define SST_FILL_DESTINATION1(dst, id)                         do {    \
+               SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF);               \
+               SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16);     \
+       } while (0)
+#define SST_FILL_DESTINATION2(dst, loc_id, mod_id)             do {    \
+               SST_FILL_LOCATION_ID(dst, loc_id);                      \
+               SST_FILL_MODULE_ID(dst, mod_id);                        \
+       } while (0)
+#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id)  do {    \
+               SST_FILL_LOCATION_IDS(dst, cell_idx, path_id);          \
+               SST_FILL_MODULE_ID(dst, mod_id);                        \
+       } while (0)
+
+#define SST_FILL_DESTINATION(level, dst, ...)                          \
+       SST_FILL_DESTINATION##level(dst, __VA_ARGS__)
+#define SST_FILL_DEFAULT_DESTINATION(dst)                              \
+       SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID)
+
+struct sst_destination_id {
+       union sst_location_id {
+               struct {
+                       u8 cell_nbr_idx;        /* module index */
+                       u8 path_id;             /* pipe_id */
+               } __packed      p;              /* part */
+               u16             f;              /* full */
+       } __packed location_id;
+       u16        module_id;
+} __packed;
+struct sst_dsp_header {
+       struct sst_destination_id dst;
+       u16 command_id;
+       u16 length;
+} __packed;
+
+/*
+ *
+ * Common Commands
+ *
+ */
+struct sst_cmd_generic {
+       struct sst_dsp_header header;
+} __packed;
+
+struct swm_input_ids {
+       struct sst_destination_id input_id;
+} __packed;
+
+struct sst_cmd_set_swm {
+       struct sst_dsp_header header;
+       struct sst_destination_id output_id;
+       u16    switch_state;
+       u16    nb_inputs;
+       struct swm_input_ids input[SST_CMD_SWM_MAX_INPUTS];
+} __packed;
+
+struct sst_cmd_set_media_path {
+       struct sst_dsp_header header;
+       u16    switch_state;
+} __packed;
+
+struct pcm_cfg {
+               u8 s_length:2;
+               u8 rate:3;
+               u8 format:3;
+} __packed;
+
+struct sst_cmd_set_speech_path {
+       struct sst_dsp_header header;
+       u16    switch_state;
+       struct {
+               u16 rsvd:8;
+               struct pcm_cfg cfg;
+       } config;
+} __packed;
+
+struct gain_cell {
+       struct sst_destination_id dest;
+       s16 cell_gain_left;
+       s16 cell_gain_right;
+       u16 gain_time_constant;
+} __packed;
+
+#define NUM_GAIN_CELLS 1
+struct sst_cmd_set_gain_dual {
+       struct sst_dsp_header header;
+       u16    gain_cell_num;
+       struct gain_cell cell_gains[NUM_GAIN_CELLS];
+} __packed;
+struct sst_cmd_set_params {
+       struct sst_destination_id dst;
+       u16 command_id;
+       char params[0];
+} __packed;
+
+
+struct sst_cmd_sba_vb_start {
+       struct sst_dsp_header header;
+} __packed;
+
+union sba_media_loop_params {
+       struct {
+               u16 rsvd:8;
+               struct pcm_cfg cfg;
+       } part;
+       u16 full;
+} __packed;
+
+struct sst_cmd_sba_set_media_loop_map {
+       struct  sst_dsp_header header;
+       u16     switch_state;
+       union   sba_media_loop_params param;
+       u16     map;
+} __packed;
+
+struct sst_cmd_tone_stop {
+       struct  sst_dsp_header header;
+       u16     switch_state;
+} __packed;
+
+enum sst_ssp_mode {
+       SSP_MODE_MASTER = 0,
+       SSP_MODE_SLAVE = 1,
+};
+
+enum sst_ssp_pcm_mode {
+       SSP_PCM_MODE_NORMAL = 0,
+       SSP_PCM_MODE_NETWORK = 1,
+};
+
+enum sst_ssp_duplex {
+       SSP_DUPLEX = 0,
+       SSP_RX = 1,
+       SSP_TX = 2,
+};
+
+enum sst_ssp_fs_frequency {
+       SSP_FS_8_KHZ = 0,
+       SSP_FS_16_KHZ = 1,
+       SSP_FS_44_1_KHZ = 2,
+       SSP_FS_48_KHZ = 3,
+};
+
+enum sst_ssp_fs_polarity {
+       SSP_FS_ACTIVE_LOW = 0,
+       SSP_FS_ACTIVE_HIGH = 1,
+};
+
+enum sst_ssp_protocol {
+       SSP_MODE_PCM = 0,
+       SSP_MODE_I2S = 1,
+};
+
+enum sst_ssp_port_id {
+       SSP_MODEM = 0,
+       SSP_BT = 1,
+       SSP_FM = 2,
+       SSP_CODEC = 3,
+};
+
+struct sst_cmd_sba_hw_set_ssp {
+       struct sst_dsp_header header;
+       u16 selection;                  /* 0:SSP0(def), 1:SSP1, 2:SSP2 */
+
+       u16 switch_state;
+
+       u16 nb_bits_per_slots:6;        /* 0-32 bits, 24 (def) */
+       u16 nb_slots:4;                 /* 0-8: slots per frame  */
+       u16 mode:3;                     /* 0:Master, 1: Slave  */
+       u16 duplex:3;
+
+       u16 active_tx_slot_map:8;       /* Bit map, 0:off, 1:on */
+       u16 reserved1:8;
+
+       u16 active_rx_slot_map:8;       /* Bit map 0: Off, 1:On */
+       u16 reserved2:8;
+
+       u16 frame_sync_frequency;
+
+       u16 frame_sync_polarity:8;
+       u16 data_polarity:8;
+
+       u16 frame_sync_width;           /* 1 to N clocks */
+       u16 ssp_protocol:8;
+       u16 start_delay:8;              /* Start delay in terms of clock ticks */
+} __packed;
+
+#define SST_MAX_TDM_SLOTS 8
+
+struct sst_param_sba_ssp_slot_map {
+       struct sst_dsp_header header;
+
+       u16 param_id;
+       u16 param_len;
+       u16 ssp_index;
+
+       u8 rx_slot_map[SST_MAX_TDM_SLOTS];
+       u8 tx_slot_map[SST_MAX_TDM_SLOTS];
+} __packed;
+
+enum {
+       SST_PROBE_EXTRACTOR = 0,
+       SST_PROBE_INJECTOR = 1,
+};
+
+/**** widget defines *****/
+
+#define SST_MODULE_GAIN 1
+#define SST_MODULE_ALGO 2
+
+#define SST_FMT_MONO 0
+#define SST_FMT_STEREO 3
+
+/* physical SSP numbers */
+enum {
+       SST_SSP0 = 0,
+       SST_SSP1,
+       SST_SSP2,
+       SST_SSP_LAST = SST_SSP2,
+};
+
+#define SST_NUM_SSPS           (SST_SSP_LAST + 1)      /* physical SSPs */
+#define SST_MAX_SSP_MUX                2                       /* single SSP muxed between pipes */
+#define SST_MAX_SSP_DOMAINS    2                       /* domains present in each pipe */
+
+struct sst_module {
+       struct snd_kcontrol *kctl;
+       struct list_head node;
+};
+
+struct sst_ssp_config {
+       u8 ssp_id;
+       u8 bits_per_slot;
+       u8 slots;
+       u8 ssp_mode;
+       u8 pcm_mode;
+       u8 duplex;
+       u8 ssp_protocol;
+       u8 fs_frequency;
+       u8 active_slot_map;
+       u8 start_delay;
+       u16 fs_width;
+};
+
+struct sst_ssp_cfg {
+       const u8 ssp_number;
+       const int *mux_shift;
+       const int (*domain_shift)[SST_MAX_SSP_MUX];
+       const struct sst_ssp_config (*ssp_config)[SST_MAX_SSP_MUX][SST_MAX_SSP_DOMAINS];
+};
+
+struct sst_ids {
+       u16 location_id;
+       u16 module_id;
+       u8  task_id;
+       u8  format;
+       u8  reg;
+       const char *parent_wname;
+       struct snd_soc_dapm_widget *parent_w;
+       struct list_head algo_list;
+       struct list_head gain_list;
+       const struct sst_pcm_format *pcm_fmt;
+};
+
+
+#define SST_AIF_IN(wname, wevent)                                                      \
+{      .id = snd_soc_dapm_aif_in, .name = wname, .sname = NULL,                        \
+       .reg = SND_SOC_NOPM, .shift = 0,                                        \
+       .on_val = 1, .off_val = 0,                                                      \
+       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
+       .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 }            \
+}
+
+#define SST_AIF_OUT(wname, wevent)                                                     \
+{      .id = snd_soc_dapm_aif_out, .name = wname, .sname = NULL,                       \
+       .reg = SND_SOC_NOPM, .shift = 0,                                                \
+       .on_val = 1, .off_val = 0,                                                      \
+       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
+       .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 }            \
+}
+
+#define SST_INPUT(wname, wevent)                                                       \
+{      .id = snd_soc_dapm_input, .name = wname, .sname = NULL,                         \
+       .reg = SND_SOC_NOPM, .shift = 0,                                                \
+       .on_val = 1, .off_val = 0,                                                      \
+       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
+       .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 }            \
+}
+
+#define SST_OUTPUT(wname, wevent)                                                      \
+{      .id = snd_soc_dapm_output, .name = wname, .sname = NULL,                        \
+       .reg = SND_SOC_NOPM, .shift = 0,                                                \
+       .on_val = 1, .off_val = 0,                                                      \
+       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
+       .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 }            \
+}
+
+#define SST_DAPM_OUTPUT(wname, wloc_id, wtask_id, wformat, wevent)                      \
+{      .id = snd_soc_dapm_output, .name = wname, .sname = NULL,                        \
+       .reg = SND_SOC_NOPM, .shift = 0,                                                \
+       .on_val = 1, .off_val = 0,                                                      \
+       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
+       .priv = (void *)&(struct sst_ids) { .location_id = wloc_id, .task_id = wtask_id,\
+                                               .pcm_fmt = wformat, }                   \
+}
+
+#define SST_PATH(wname, wtask, wloc_id, wevent, wflags)                                        \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0,         \
+       .kcontrol_news = NULL, .num_kcontrols = 0,                              \
+       .on_val = 1, .off_val = 0,                                                      \
+       .event = wevent, .event_flags = wflags,                                         \
+       .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, } \
+}
+
+#define SST_LINKED_PATH(wname, wtask, wloc_id, linked_wname, wevent, wflags)           \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0,         \
+       .kcontrol_news = NULL, .num_kcontrols = 0,                              \
+       .on_val = 1, .off_val = 0,                                                      \
+       .event = wevent, .event_flags = wflags,                                         \
+       .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id,   \
+                                       .parent_wname = linked_wname}                   \
+}
+
+#define SST_PATH_MEDIA_LOOP(wname, wtask, wloc_id, wformat, wevent, wflags)             \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0,         \
+       .kcontrol_news = NULL, .num_kcontrols = 0,                         \
+       .event = wevent, .event_flags = wflags,                                         \
+       .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id,   \
+                                           .format = wformat,}                         \
+}
+
+/* output is triggered before input */
+#define SST_PATH_INPUT(name, task_id, loc_id, event)                                   \
+       SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
+
+#define SST_PATH_LINKED_INPUT(name, task_id, loc_id, linked_wname, event)              \
+       SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event,                     \
+                                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
+
+#define SST_PATH_OUTPUT(name, task_id, loc_id, event)                                  \
+       SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
+
+#define SST_PATH_LINKED_OUTPUT(name, task_id, loc_id, linked_wname, event)             \
+       SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event,                     \
+                                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
+
+#define SST_PATH_MEDIA_LOOP_OUTPUT(name, task_id, loc_id, format, event)               \
+       SST_PATH_MEDIA_LOOP(name, task_id, loc_id, format, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
+
+
+#define SST_SWM_MIXER(wname, wreg, wtask, wloc_id, wcontrols, wevent)                  \
+{      .id = snd_soc_dapm_mixer, .name = wname, .reg = SND_SOC_NOPM, .shift = 0,       \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols),\
+       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD |  \
+                                       SND_SOC_DAPM_POST_REG,                          \
+       .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id,   \
+                                           .reg = wreg }                               \
+}
+
+enum sst_gain_kcontrol_type {
+       SST_GAIN_TLV,
+       SST_GAIN_MUTE,
+       SST_GAIN_RAMP_DURATION,
+};
+
+struct sst_gain_mixer_control {
+       bool stereo;
+       enum sst_gain_kcontrol_type type;
+       struct sst_gain_value *gain_val;
+       int max;
+       int min;
+       u16 instance_id;
+       u16 module_id;
+       u16 pipe_id;
+       u16 task_id;
+       char pname[44];
+       struct snd_soc_dapm_widget *w;
+};
+
+struct sst_gain_value {
+       u16 ramp_duration;
+       s16 l_gain;
+       s16 r_gain;
+       bool mute;
+};
+#define SST_GAIN_VOLUME_DEFAULT                (-1440)
+#define SST_GAIN_RAMP_DURATION_DEFAULT 5 /* timeconstant */
+#define SST_GAIN_MUTE_DEFAULT          true
+
+#define SST_GAIN_KCONTROL_TLV(xname, xhandler_get, xhandler_put, \
+                             xmod, xpipe, xinstance, xtask, tlv_array, xgain_val, \
+                             xmin, xmax, xpname) \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+                 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .tlv.p = (tlv_array), \
+       .info = sst_gain_ctl_info,\
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
+       { .stereo = true, .max = xmax, .min = xmin, .type = SST_GAIN_TLV, \
+         .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
+         .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
+
+#define SST_GAIN_KCONTROL_INT(xname, xhandler_get, xhandler_put, \
+                             xmod, xpipe, xinstance, xtask, xtype, xgain_val, \
+                             xmin, xmax, xpname) \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = sst_gain_ctl_info, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
+       { .stereo = false, .max = xmax, .min = xmin, .type = xtype, \
+         .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
+         .instance_id = xinstance, .gain_val = xgain_val, .pname =  xpname}
+
+#define SST_GAIN_KCONTROL_BOOL(xname, xhandler_get, xhandler_put,\
+                              xmod, xpipe, xinstance, xtask, xgain_val, xpname) \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_bool_ext, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
+       { .stereo = false, .type = SST_GAIN_MUTE, \
+         .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
+         .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
+#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
+       xpname " " xmname " " #xinstance " " xtype
+
+#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
+       xpname " " xmname " " #xinstance " " xtype " " xsubmodule
+
+/*
+ * 3 Controls for each Gain module
+ * e.g.        - pcm0_in Gain 0 Volume
+ *     - pcm0_in Gain 0 Ramp Delay
+ *     - pcm0_in Gain 0 Switch
+ */
+#define SST_GAIN_KCONTROLS(xpname, xmname, xmin_gain, xmax_gain, xmin_tc, xmax_tc, \
+                          xhandler_get, xhandler_put, \
+                          xmod, xpipe, xinstance, xtask, tlv_array, xgain_val) \
+       { SST_GAIN_KCONTROL_INT(SST_CONTROL_NAME(xpname, xmname, xinstance, "Ramp Delay"), \
+               xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, SST_GAIN_RAMP_DURATION, \
+               xgain_val, xmin_tc, xmax_tc, xpname) }, \
+       { SST_GAIN_KCONTROL_BOOL(SST_CONTROL_NAME(xpname, xmname, xinstance, "Switch"), \
+               xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, \
+               xgain_val, xpname) } ,\
+       { SST_GAIN_KCONTROL_TLV(SST_CONTROL_NAME(xpname, xmname, xinstance, "Volume"), \
+               xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, tlv_array, \
+               xgain_val, xmin_gain, xmax_gain, xpname) }
+
+#define SST_GAIN_TC_MIN                5
+#define SST_GAIN_TC_MAX                5000
+#define SST_GAIN_MIN_VALUE     -1440 /* in 0.1 DB units */
+#define SST_GAIN_MAX_VALUE     360
+
+enum sst_algo_kcontrol_type {
+       SST_ALGO_PARAMS,
+       SST_ALGO_BYPASS,
+};
+
+struct sst_algo_control {
+       enum sst_algo_kcontrol_type type;
+       int max;
+       u16 module_id;
+       u16 pipe_id;
+       u16 task_id;
+       u16 cmd_id;
+       bool bypass;
+       unsigned char *params;
+       struct snd_soc_dapm_widget *w;
+};
+
+/* size of the control = size of params + size of length field */
+#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd)                    \
+       (struct sst_algo_control){                                                      \
+               .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod,                  \
+               .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd,                     \
+       }
+
+#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe,                                  \
+                         xtask, xcmd, xtype, xinfo, xget, xput)                        \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,                                            \
+       .name =  xname,                                                                 \
+       .info = xinfo, .get = xget, .put = xput,                                        \
+       .private_value = (unsigned long)&                                               \
+                       SST_ALGO_CTL_VALUE(xcount, xtype, xpipe,                        \
+                                          xmod, xtask, xcmd),                          \
+}
+
+#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod,                          \
+                               xpipe, xinstance, xtask, xcmd)                          \
+       SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"),        \
+                         xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,            \
+                         sst_algo_bytes_ctl_info,                                      \
+                         sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask)          \
+       SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"),        \
+                         0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS,                    \
+                         snd_soc_info_bool_ext,                                        \
+                         sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe,                    \
+                               xinstance, xtask, xcmd)                                 \
+       SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask),          \
+       SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd)
+
+#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod,           \
+                                     xpipe, xinstance, xtask, xcmd)                    \
+       SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params",   \
+                                                xsubmod),                              \
+                         xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,            \
+                         sst_algo_bytes_ctl_info,                                      \
+                         sst_algo_control_get, sst_algo_control_set)
+
+
+struct sst_enum {
+       bool tx;
+       unsigned short reg;
+       unsigned int max;
+       const char * const *texts;
+       struct snd_soc_dapm_widget *w;
+};
+
+/* only 4 slots/channels supported atm */
+#define SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts) \
+       (struct sst_enum){ .reg = s_ch_no, .tx = is_tx, .max = 4+1, .texts = xtexts, }
+
+#define SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name) \
+       xpname " " xmname " " s_ch_name
+
+#define SST_SSP_SLOT_CTL(xpname, xmname, s_ch_name, s_ch_no, is_tx, xtexts, xget, xput) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name), \
+       .info = sst_slot_enum_info, \
+       .get = xget, .put = xput, \
+       .private_value = (unsigned long)&SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts), \
+}
+
+#define SST_MUX_CTL_NAME(xpname, xinstance) \
+       xpname " " #xinstance
+
+#define SST_SSP_MUX_ENUM(xreg, xshift, xtexts) \
+       (struct soc_enum) SOC_ENUM_DOUBLE(xreg, xshift, xshift, ARRAY_SIZE(xtexts), xtexts)
+
+#define SST_SSP_MUX_CTL(xpname, xinstance, xreg, xshift, xtexts) \
+       SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \
+                         SST_SSP_MUX_ENUM(xreg, xshift, xtexts))
+
+#endif
diff --git a/sound/soc/intel/atom/sst-mfld-dsp.h b/sound/soc/intel/atom/sst-mfld-dsp.h
new file mode 100644 (file)
index 0000000..4257263
--- /dev/null
@@ -0,0 +1,533 @@
+#ifndef __SST_MFLD_DSP_H__
+#define __SST_MFLD_DSP_H__
+/*
+ *  sst_mfld_dsp.h - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-14 Intel Corporation
+ *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define SST_MAX_BIN_BYTES 1024
+
+#define MAX_DBG_RW_BYTES 80
+#define MAX_NUM_SCATTER_BUFFERS 8
+#define MAX_LOOP_BACK_DWORDS 8
+/* IPC base address and mailbox, timestamp offsets */
+#define SST_MAILBOX_SIZE 0x0400
+#define SST_MAILBOX_SEND 0x0000
+#define SST_TIME_STAMP 0x1800
+#define SST_TIME_STAMP_MRFLD 0x800
+#define SST_RESERVED_OFFSET 0x1A00
+#define SST_SCU_LPE_MAILBOX 0x1000
+#define SST_LPE_SCU_MAILBOX 0x1400
+#define SST_SCU_LPE_LOG_BUF (SST_SCU_LPE_MAILBOX+16)
+#define PROCESS_MSG 0x80
+
+/* Message ID's for IPC messages */
+/* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */
+
+/* I2L Firmware/Codec Download msgs */
+#define IPC_IA_PREP_LIB_DNLD 0x01
+#define IPC_IA_LIB_DNLD_CMPLT 0x02
+#define IPC_IA_GET_FW_VERSION 0x04
+#define IPC_IA_GET_FW_BUILD_INF 0x05
+#define IPC_IA_GET_FW_INFO 0x06
+#define IPC_IA_GET_FW_CTXT 0x07
+#define IPC_IA_SET_FW_CTXT 0x08
+#define IPC_IA_PREPARE_SHUTDOWN 0x31
+/* I2L Codec Config/control msgs */
+#define IPC_PREP_D3 0x10
+#define IPC_IA_SET_CODEC_PARAMS 0x10
+#define IPC_IA_GET_CODEC_PARAMS 0x11
+#define IPC_IA_SET_PPP_PARAMS 0x12
+#define IPC_IA_GET_PPP_PARAMS 0x13
+#define IPC_SST_PERIOD_ELAPSED_MRFLD 0xA
+#define IPC_IA_ALG_PARAMS 0x1A
+#define IPC_IA_TUNING_PARAMS 0x1B
+#define IPC_IA_SET_RUNTIME_PARAMS 0x1C
+#define IPC_IA_SET_PARAMS 0x1
+#define IPC_IA_GET_PARAMS 0x2
+
+#define IPC_EFFECTS_CREATE 0xE
+#define IPC_EFFECTS_DESTROY 0xF
+
+/* I2L Stream config/control msgs */
+#define IPC_IA_ALLOC_STREAM_MRFLD 0x2
+#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */
+#define IPC_IA_FREE_STREAM_MRFLD 0x03
+#define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */
+#define IPC_IA_SET_STREAM_PARAMS 0x22
+#define IPC_IA_SET_STREAM_PARAMS_MRFLD 0x12
+#define IPC_IA_GET_STREAM_PARAMS 0x23
+#define IPC_IA_PAUSE_STREAM 0x24
+#define IPC_IA_PAUSE_STREAM_MRFLD 0x4
+#define IPC_IA_RESUME_STREAM 0x25
+#define IPC_IA_RESUME_STREAM_MRFLD 0x5
+#define IPC_IA_DROP_STREAM 0x26
+#define IPC_IA_DROP_STREAM_MRFLD 0x07
+#define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */
+#define IPC_IA_DRAIN_STREAM_MRFLD 0x8
+#define IPC_IA_CONTROL_ROUTING 0x29
+#define IPC_IA_VTSV_UPDATE_MODULES 0x20
+#define IPC_IA_VTSV_DETECTED 0x21
+
+#define IPC_IA_START_STREAM_MRFLD 0X06
+#define IPC_IA_START_STREAM 0x30 /* Short msg with str_id */
+
+#define IPC_IA_SET_GAIN_MRFLD 0x21
+/* Debug msgs */
+#define IPC_IA_DBG_MEM_READ 0x40
+#define IPC_IA_DBG_MEM_WRITE 0x41
+#define IPC_IA_DBG_LOOP_BACK 0x42
+#define IPC_IA_DBG_LOG_ENABLE 0x45
+#define IPC_IA_DBG_SET_PROBE_PARAMS 0x47
+
+/* L2I Firmware/Codec Download msgs */
+#define IPC_IA_FW_INIT_CMPLT 0x81
+#define IPC_IA_FW_INIT_CMPLT_MRFLD 0x01
+#define IPC_IA_FW_ASYNC_ERR_MRFLD 0x11
+
+/* L2I Codec Config/control msgs */
+#define IPC_SST_FRAGMENT_ELPASED 0x90 /* Request IA more data */
+
+#define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */
+#define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */
+#define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */
+#define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */
+#define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/* error in processing a stream */
+#define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */
+
+#define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occurred */
+/* L2S messages */
+#define IPC_SC_DDR_LINK_UP 0xC0
+#define IPC_SC_DDR_LINK_DOWN 0xC1
+#define IPC_SC_SET_LPECLK_REQ 0xC2
+#define IPC_SC_SSP_BIT_BANG 0xC3
+
+/* L2I Error reporting msgs */
+#define IPC_IA_MEM_ALLOC_FAIL 0xE0
+#define IPC_IA_PROC_ERR 0xE1 /* error in processing a
+                                       stream can be used by playback and
+                                       capture modules */
+
+/* L2I Debug msgs */
+#define IPC_IA_PRINT_STRING 0xF0
+
+/* Buffer under-run */
+#define IPC_IA_BUF_UNDER_RUN_MRFLD 0x0B
+
+/* Mrfld specific defines:
+ * For asynchronous messages(INIT_CMPLT, PERIOD_ELAPSED, ASYNC_ERROR)
+ * received from FW, the format is:
+ *  - IPC High: pvt_id is set to zero. Always short message.
+ *  - msg_id is in lower 16-bits of IPC low payload.
+ *  - pipe_id is in higher 16-bits of IPC low payload for period_elapsed.
+ *  - error id is in higher 16-bits of IPC low payload for async errors.
+ */
+#define SST_ASYNC_DRV_ID 0
+
+/* Command Response or Acknowledge message to any IPC message will have
+ * same message ID and stream ID information which is sent.
+ * There is no specific Ack message ID. The data field is used as response
+ * meaning.
+ */
+enum ackData {
+       IPC_ACK_SUCCESS = 0,
+       IPC_ACK_FAILURE,
+};
+
+enum ipc_ia_msg_id {
+       IPC_CMD = 1,            /*!< Task Control message ID */
+       IPC_SET_PARAMS = 2,/*!< Task Set param message ID */
+       IPC_GET_PARAMS = 3,     /*!< Task Get param message ID */
+       IPC_INVALID = 0xFF,     /*!<Task Get param message ID */
+};
+
+enum sst_codec_types {
+       /*  AUDIO/MUSIC CODEC Type Definitions */
+       SST_CODEC_TYPE_UNKNOWN = 0,
+       SST_CODEC_TYPE_PCM,     /* Pass through Audio codec */
+       SST_CODEC_TYPE_MP3,
+       SST_CODEC_TYPE_MP24,
+       SST_CODEC_TYPE_AAC,
+       SST_CODEC_TYPE_AACP,
+       SST_CODEC_TYPE_eAACP,
+};
+
+enum stream_type {
+       SST_STREAM_TYPE_NONE = 0,
+       SST_STREAM_TYPE_MUSIC = 1,
+};
+
+enum sst_error_codes {
+       /* Error code,response to msgId: Description */
+       /* Common error codes */
+       SST_SUCCESS = 0,        /* Success */
+       SST_ERR_INVALID_STREAM_ID = 1,
+       SST_ERR_INVALID_MSG_ID = 2,
+       SST_ERR_INVALID_STREAM_OP = 3,
+       SST_ERR_INVALID_PARAMS = 4,
+       SST_ERR_INVALID_CODEC = 5,
+       SST_ERR_INVALID_MEDIA_TYPE = 6,
+       SST_ERR_STREAM_ERR = 7,
+
+       SST_ERR_STREAM_IN_USE = 15,
+};
+
+struct ipc_dsp_hdr {
+       u16 mod_index_id:8;             /*!< DSP Command ID specific to tasks */
+       u16 pipe_id:8;  /*!< instance of the module in the pipeline */
+       u16 mod_id;             /*!< Pipe_id */
+       u16 cmd_id;             /*!< Module ID = lpe_algo_types_t */
+       u16 length;             /*!< Length of the payload only */
+} __packed;
+
+union ipc_header_high {
+       struct {
+               u32  msg_id:8;      /* Message ID - Max 256 Message Types */
+               u32  task_id:4;     /* Task ID associated with this comand */
+               u32  drv_id:4;    /* Identifier for the driver to track*/
+               u32  rsvd1:8;       /* Reserved */
+               u32  result:4;      /* Reserved */
+               u32  res_rqd:1;     /* Response rqd */
+               u32  large:1;       /* Large Message if large = 1 */
+               u32  done:1;        /* bit 30 - Done bit */
+               u32  busy:1;        /* bit 31 - busy bit*/
+       } part;
+       u32 full;
+} __packed;
+/* IPC header */
+union ipc_header_mrfld {
+       struct {
+               u32 header_low_payload;
+               union ipc_header_high header_high;
+       } p;
+       u64 full;
+} __packed;
+/* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/
+
+/* IPC Header */
+union ipc_header {
+       struct {
+               u32  msg_id:8; /* Message ID - Max 256 Message Types */
+               u32  str_id:5;
+               u32  large:1;   /* Large Message if large = 1 */
+               u32  reserved:2;        /* Reserved for future use */
+               u32  data:14;   /* Ack/Info for msg, size of msg in Mailbox */
+               u32  done:1; /* bit 30 */
+               u32  busy:1; /* bit 31 */
+       } part;
+       u32 full;
+} __packed;
+
+/* Firmware build info */
+struct sst_fw_build_info {
+       unsigned char  date[16]; /* Firmware build date */
+       unsigned char  time[16]; /* Firmware build time */
+} __packed;
+
+/* Firmware Version info */
+struct snd_sst_fw_version {
+       u8 build;       /* build number*/
+       u8 minor;       /* minor number*/
+       u8 major;       /* major number*/
+       u8 type;        /* build type */
+};
+
+struct ipc_header_fw_init {
+       struct snd_sst_fw_version fw_version;/* Firmware version details */
+       struct sst_fw_build_info build_info;
+       u16 result;     /* Fw init result */
+       u8 module_id; /* Module ID in case of error */
+       u8 debug_info; /* Debug info from Module ID in case of fail */
+} __packed;
+
+struct snd_sst_tstamp {
+       u64 ring_buffer_counter;        /* PB/CP: Bytes copied from/to DDR. */
+       u64 hardware_counter;       /* PB/CP: Bytes DMAed to/from SSP. */
+       u64 frames_decoded;
+       u64 bytes_decoded;
+       u64 bytes_copied;
+       u32 sampling_frequency;
+       u32 channel_peak[8];
+} __packed;
+
+/* Stream type params struture for Alloc stream */
+struct snd_sst_str_type {
+       u8 codec_type;          /* Codec type */
+       u8 str_type;            /* 1 = voice 2 = music */
+       u8 operation;           /* Playback or Capture */
+       u8 protected_str;       /* 0=Non DRM, 1=DRM */
+       u8 time_slots;
+       u8 reserved;            /* Reserved */
+       u16 result;             /* Result used for acknowledgment */
+} __packed;
+
+/* Library info structure */
+struct module_info {
+       u32 lib_version;
+       u32 lib_type;/*TBD- KLOCKWORK u8 lib_type;*/
+       u32 media_type;
+       u8  lib_name[12];
+       u32 lib_caps;
+       unsigned char  b_date[16]; /* Lib build date */
+       unsigned char  b_time[16]; /* Lib build time */
+} __packed;
+
+/* Library slot info */
+struct lib_slot_info {
+       u8  slot_num; /* 1 or 2 */
+       u8  reserved1;
+       u16 reserved2;
+       u32 iram_size; /* slot size in IRAM */
+       u32 dram_size; /* slot size in DRAM */
+       u32 iram_offset; /* starting offset of slot in IRAM */
+       u32 dram_offset; /* starting offset of slot in DRAM */
+} __packed;
+
+struct snd_ppp_mixer_params {
+       __u32                   type; /*Type of the parameter */
+       __u32                   size;
+       __u32                   input_stream_bitmap; /*Input stream Bit Map*/
+} __packed;
+
+struct snd_sst_lib_download {
+       struct module_info lib_info; /* library info type, capabilities etc */
+       struct lib_slot_info slot_info; /* slot info to be downloaded */
+       u32 mod_entry_pt;
+};
+
+struct snd_sst_lib_download_info {
+       struct snd_sst_lib_download dload_lib;
+       u16 result;     /* Result used for acknowledgment */
+       u8 pvt_id; /* Private ID */
+       u8 reserved;  /* for alignment */
+};
+struct snd_pcm_params {
+       u8 num_chan;    /* 1=Mono, 2=Stereo */
+       u8 pcm_wd_sz;   /* 16/24 - bit*/
+       u8 use_offload_path;    /* 0-PCM using period elpased & ALSA interfaces
+                                  1-PCM stream via compressed interface  */
+       u8 reserved2;
+       u32 sfreq;    /* Sampling rate in Hz */
+       u8 channel_map[8];
+} __packed;
+
+/* MP3 Music Parameters Message */
+struct snd_mp3_params {
+       u8  num_chan;   /* 1=Mono, 2=Stereo     */
+       u8  pcm_wd_sz; /* 16/24 - bit*/
+       u8  crc_check; /* crc_check - disable (0) or enable (1) */
+       u8  reserved1; /* unused*/
+       u16 reserved2;  /* Unused */
+} __packed;
+
+#define AAC_BIT_STREAM_ADTS            0
+#define AAC_BIT_STREAM_ADIF            1
+#define AAC_BIT_STREAM_RAW             2
+
+/* AAC Music Parameters Message */
+struct snd_aac_params {
+       u8 num_chan; /* 1=Mono, 2=Stereo*/
+       u8 pcm_wd_sz; /* 16/24 - bit*/
+       u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */
+       u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
+       u16  reser2;
+       u32 externalsr; /*sampling rate of basic AAC raw bit stream*/
+       u8 sbr_signalling;/*disable/enable/set automode the SBR tool.AAC+*/
+       u8 reser1;
+       u16  reser3;
+} __packed;
+
+/* WMA Music Parameters Message */
+struct snd_wma_params {
+       u8  num_chan;   /* 1=Mono, 2=Stereo */
+       u8  pcm_wd_sz;  /* 16/24 - bit*/
+       u16 reserved1;
+       u32 brate;      /* Use the hard coded value. */
+       u32 sfreq;      /* Sampling freq eg. 8000, 441000, 48000 */
+       u32 channel_mask;  /* Channel Mask */
+       u16 format_tag; /* Format Tag */
+       u16 block_align;        /* packet size */
+       u16 wma_encode_opt;/* Encoder option */
+       u8 op_align;    /* op align 0- 16 bit, 1- MSB, 2 LSB */
+       u8 reserved;    /* reserved */
+} __packed;
+
+/* Codec params struture */
+union  snd_sst_codec_params {
+       struct snd_pcm_params pcm_params;
+       struct snd_mp3_params mp3_params;
+       struct snd_aac_params aac_params;
+       struct snd_wma_params wma_params;
+} __packed;
+
+/* Address and size info of a frame buffer */
+struct sst_address_info {
+       u32 addr; /* Address at IA */
+       u32 size; /* Size of the buffer */
+};
+
+struct snd_sst_alloc_params_ext {
+       __u16 sg_count;
+       __u16 reserved;
+       __u32 frag_size;        /*Number of samples after which period elapsed
+                                 message is sent valid only if path  = 0*/
+       struct sst_address_info  ring_buf_info[8];
+};
+
+struct snd_sst_stream_params {
+       union snd_sst_codec_params uc;
+} __packed;
+
+struct snd_sst_params {
+       u32 result;
+       u32 stream_id;
+       u8 codec;
+       u8 ops;
+       u8 stream_type;
+       u8 device_type;
+       u8 task;
+       struct snd_sst_stream_params sparams;
+       struct snd_sst_alloc_params_ext aparams;
+};
+
+struct snd_sst_alloc_mrfld {
+       u16 codec_type;
+       u8 operation;
+       u8 sg_count;
+       struct sst_address_info ring_buf_info[8];
+       u32 frag_size;
+       u32 ts;
+       struct snd_sst_stream_params codec_params;
+} __packed;
+
+/* Alloc stream params structure */
+struct snd_sst_alloc_params {
+       struct snd_sst_str_type str_type;
+       struct snd_sst_stream_params stream_params;
+       struct snd_sst_alloc_params_ext alloc_params;
+} __packed;
+
+/* Alloc stream response message */
+struct snd_sst_alloc_response {
+       struct snd_sst_str_type str_type; /* Stream type for allocation */
+       struct snd_sst_lib_download lib_dnld; /* Valid only for codec dnld */
+};
+
+/* Drop response */
+struct snd_sst_drop_response {
+       u32 result;
+       u32 bytes;
+};
+
+struct snd_sst_async_msg {
+       u32 msg_id; /* Async msg id */
+       u32 payload[0];
+};
+
+struct snd_sst_async_err_msg {
+       u32 fw_resp; /* Firmware Result */
+       u32 lib_resp; /*Library result */
+} __packed;
+
+struct snd_sst_vol {
+       u32     stream_id;
+       s32     volume;
+       u32     ramp_duration;
+       u32     ramp_type;              /* Ramp type, default=0 */
+};
+
+/* Gain library parameters for mrfld
+ * based on DSP command spec v0.82
+ */
+struct snd_sst_gain_v2 {
+       u16 gain_cell_num;  /* num of gain cells to modify*/
+       u8 cell_nbr_idx; /* instance index*/
+       u8 cell_path_idx; /* pipe-id */
+       u16 module_id; /*module id */
+       u16 left_cell_gain; /* left gain value in dB*/
+       u16 right_cell_gain; /* right gain value in dB*/
+       u16 gain_time_const; /* gain time constant*/
+} __packed;
+
+struct snd_sst_mute {
+       u32     stream_id;
+       u32     mute;
+};
+
+struct snd_sst_runtime_params {
+       u8 type;
+       u8 str_id;
+       u8 size;
+       u8 rsvd;
+       void *addr;
+} __packed;
+
+enum stream_param_type {
+       SST_SET_TIME_SLOT = 0,
+       SST_SET_CHANNEL_INFO = 1,
+       OTHERS = 2, /*reserved for future params*/
+};
+
+/* CSV Voice call routing structure */
+struct snd_sst_control_routing {
+       u8 control; /* 0=start, 1=Stop */
+       u8 reserved[3]; /* Reserved- for 32 bit alignment */
+};
+
+struct ipc_post {
+       struct list_head node;
+       union ipc_header header; /* driver specific */
+       bool is_large;
+       bool is_process_reply;
+       union ipc_header_mrfld mrfld_header;
+       char *mailbox_data;
+};
+
+struct snd_sst_ctxt_params {
+       u32 address; /* Physical Address in DDR where the context is stored */
+       u32 size; /* size of the context */
+};
+
+struct snd_sst_lpe_log_params {
+       u8 dbg_type;
+       u8 module_id;
+       u8 log_level;
+       u8 reserved;
+} __packed;
+
+enum snd_sst_bytes_type {
+       SND_SST_BYTES_SET = 0x1,
+       SND_SST_BYTES_GET = 0x2,
+};
+
+struct snd_sst_bytes_v2 {
+       u8 type;
+       u8 ipc_msg;
+       u8 block;
+       u8 task_id;
+       u8 pipe_id;
+       u8 rsvd;
+       u16 len;
+       char bytes[0];
+};
+
+#define MAX_VTSV_FILES 2
+struct snd_sst_vtsv_info {
+       struct sst_address_info vfiles[MAX_VTSV_FILES];
+} __packed;
+
+#endif /* __SST_MFLD_DSP_H__ */
diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c
new file mode 100644 (file)
index 0000000..3951689
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ *  sst_mfld_platform.c - Intel MID Platform driver
+ *
+ *  Copyright (C) 2010-2014 Intel Corp
+ *  Author: Vinod Koul <vinod.koul@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include "sst-mfld-platform.h"
+
+/* compress stream operations */
+static void sst_compr_fragment_elapsed(void *arg)
+{
+       struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+       pr_debug("fragment elapsed by driver\n");
+       if (cstream)
+               snd_compr_fragment_elapsed(cstream);
+}
+
+static void sst_drain_notify(void *arg)
+{
+       struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+       pr_debug("drain notify by driver\n");
+       if (cstream)
+               snd_compr_drain_notify(cstream);
+}
+
+static int sst_platform_compr_open(struct snd_compr_stream *cstream)
+{
+
+       int ret_val = 0;
+       struct snd_compr_runtime *runtime = cstream->runtime;
+       struct sst_runtime_stream *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return -ENOMEM;
+
+       spin_lock_init(&stream->status_lock);
+
+       /* get the sst ops */
+       if (!sst || !try_module_get(sst->dev->driver->owner)) {
+               pr_err("no device available to run\n");
+               ret_val = -ENODEV;
+               goto out_ops;
+       }
+       stream->compr_ops = sst->compr_ops;
+       stream->id = 0;
+
+       /* Turn on LPE */
+       sst->compr_ops->power(sst->dev, true);
+
+       sst_set_stream_status(stream, SST_PLATFORM_INIT);
+       runtime->private_data = stream;
+       return 0;
+out_ops:
+       kfree(stream);
+       return ret_val;
+}
+
+static int sst_platform_compr_free(struct snd_compr_stream *cstream)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val = 0, str_id;
+
+       stream = cstream->runtime->private_data;
+       /* Turn off LPE */
+       sst->compr_ops->power(sst->dev, false);
+
+       /*need to check*/
+       str_id = stream->id;
+       if (str_id)
+               ret_val = stream->compr_ops->close(sst->dev, str_id);
+       module_put(sst->dev->driver->owner);
+       kfree(stream);
+       pr_debug("%s: %d\n", __func__, ret_val);
+       return 0;
+}
+
+static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
+                                       struct snd_compr_params *params)
+{
+       struct sst_runtime_stream *stream;
+       int retval;
+       struct snd_sst_params str_params;
+       struct sst_compress_cb cb;
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
+
+       stream = cstream->runtime->private_data;
+       /* construct fw structure for this*/
+       memset(&str_params, 0, sizeof(str_params));
+
+       /* fill the device type and stream id to pass to SST driver */
+       retval = sst_fill_stream_params(cstream, ctx, &str_params, true);
+       pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval);
+       if (retval < 0)
+               return retval;
+
+       switch (params->codec.id) {
+       case SND_AUDIOCODEC_MP3: {
+               str_params.codec = SST_CODEC_TYPE_MP3;
+               str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
+               str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
+               break;
+       }
+
+       case SND_AUDIOCODEC_AAC: {
+               str_params.codec = SST_CODEC_TYPE_AAC;
+               str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
+               str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
+               if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
+                       str_params.sparams.uc.aac_params.bs_format =
+                                                       AAC_BIT_STREAM_ADTS;
+               else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
+                       str_params.sparams.uc.aac_params.bs_format =
+                                                       AAC_BIT_STREAM_RAW;
+               else {
+                       pr_err("Undefined format%d\n", params->codec.format);
+                       return -EINVAL;
+               }
+               str_params.sparams.uc.aac_params.externalsr =
+                                               params->codec.sample_rate;
+               break;
+       }
+
+       default:
+               pr_err("codec not supported, id =%d\n", params->codec.id);
+               return -EINVAL;
+       }
+
+       str_params.aparams.ring_buf_info[0].addr  =
+                                       virt_to_phys(cstream->runtime->buffer);
+       str_params.aparams.ring_buf_info[0].size =
+                                       cstream->runtime->buffer_size;
+       str_params.aparams.sg_count = 1;
+       str_params.aparams.frag_size = cstream->runtime->fragment_size;
+
+       cb.param = cstream;
+       cb.compr_cb = sst_compr_fragment_elapsed;
+       cb.drain_cb_param = cstream;
+       cb.drain_notify = sst_drain_notify;
+
+       retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
+       if (retval < 0) {
+               pr_err("stream allocation failed %d\n", retval);
+               return retval;
+       }
+
+       stream->id = retval;
+       return 0;
+}
+
+static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+       struct sst_runtime_stream *stream = cstream->runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (stream->compr_ops->stream_start)
+                       return stream->compr_ops->stream_start(sst->dev, stream->id);
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (stream->compr_ops->stream_drop)
+                       return stream->compr_ops->stream_drop(sst->dev, stream->id);
+       case SND_COMPR_TRIGGER_DRAIN:
+               if (stream->compr_ops->stream_drain)
+                       return stream->compr_ops->stream_drain(sst->dev, stream->id);
+       case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
+               if (stream->compr_ops->stream_partial_drain)
+                       return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (stream->compr_ops->stream_pause)
+                       return stream->compr_ops->stream_pause(sst->dev, stream->id);
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (stream->compr_ops->stream_pause_release)
+                       return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
+                                       struct snd_compr_tstamp *tstamp)
+{
+       struct sst_runtime_stream *stream;
+
+       stream  = cstream->runtime->private_data;
+       stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
+       tstamp->byte_offset = tstamp->copied_total %
+                                (u32)cstream->runtime->buffer_size;
+       pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
+       return 0;
+}
+
+static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
+                                       size_t bytes)
+{
+       struct sst_runtime_stream *stream;
+
+       stream  = cstream->runtime->private_data;
+       stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
+       stream->bytes_written += bytes;
+
+       return 0;
+}
+
+static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
+                                       struct snd_compr_caps *caps)
+{
+       struct sst_runtime_stream *stream =
+               cstream->runtime->private_data;
+
+       return stream->compr_ops->get_caps(caps);
+}
+
+static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
+                                       struct snd_compr_codec_caps *codec)
+{
+       struct sst_runtime_stream *stream =
+               cstream->runtime->private_data;
+
+       return stream->compr_ops->get_codec_caps(codec);
+}
+
+static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
+                                       struct snd_compr_metadata *metadata)
+{
+       struct sst_runtime_stream *stream  =
+                cstream->runtime->private_data;
+
+       return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
+}
+
+struct snd_compr_ops sst_platform_compr_ops = {
+
+       .open = sst_platform_compr_open,
+       .free = sst_platform_compr_free,
+       .set_params = sst_platform_compr_set_params,
+       .set_metadata = sst_platform_compr_set_metadata,
+       .trigger = sst_platform_compr_trigger,
+       .pointer = sst_platform_compr_pointer,
+       .ack = sst_platform_compr_ack,
+       .get_caps = sst_platform_compr_get_caps,
+       .get_codec_caps = sst_platform_compr_get_codec_caps,
+};
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
new file mode 100644 (file)
index 0000000..2fbaf2c
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+ *  sst_mfld_platform.c - Intel MID Platform driver
+ *
+ *  Copyright (C) 2010-2014 Intel Corp
+ *  Author: Vinod Koul <vinod.koul@intel.com>
+ *  Author: Harsha Priya <priya.harsha@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "sst-mfld-platform.h"
+#include "sst-atom-controls.h"
+
+struct sst_device *sst;
+static DEFINE_MUTEX(sst_lock);
+extern struct snd_compr_ops sst_platform_compr_ops;
+
+int sst_register_dsp(struct sst_device *dev)
+{
+       if (WARN_ON(!dev))
+               return -EINVAL;
+       if (!try_module_get(dev->dev->driver->owner))
+               return -ENODEV;
+       mutex_lock(&sst_lock);
+       if (sst) {
+               dev_err(dev->dev, "we already have a device %s\n", sst->name);
+               module_put(dev->dev->driver->owner);
+               mutex_unlock(&sst_lock);
+               return -EEXIST;
+       }
+       dev_dbg(dev->dev, "registering device %s\n", dev->name);
+       sst = dev;
+       mutex_unlock(&sst_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_register_dsp);
+
+int sst_unregister_dsp(struct sst_device *dev)
+{
+       if (WARN_ON(!dev))
+               return -EINVAL;
+       if (dev != sst)
+               return -EINVAL;
+
+       mutex_lock(&sst_lock);
+
+       if (!sst) {
+               mutex_unlock(&sst_lock);
+               return -EIO;
+       }
+
+       module_put(sst->dev->driver->owner);
+       dev_dbg(dev->dev, "unreg %s\n", sst->name);
+       sst = NULL;
+       mutex_unlock(&sst_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_unregister_dsp);
+
+static struct snd_pcm_hardware sst_platform_pcm_hw = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED |
+                       SNDRV_PCM_INFO_DOUBLE |
+                       SNDRV_PCM_INFO_PAUSE |
+                       SNDRV_PCM_INFO_RESUME |
+                       SNDRV_PCM_INFO_MMAP|
+                       SNDRV_PCM_INFO_MMAP_VALID |
+                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                       SNDRV_PCM_INFO_SYNC_START),
+       .buffer_bytes_max = SST_MAX_BUFFER,
+       .period_bytes_min = SST_MIN_PERIOD_BYTES,
+       .period_bytes_max = SST_MAX_PERIOD_BYTES,
+       .periods_min = SST_MIN_PERIODS,
+       .periods_max = SST_MAX_PERIODS,
+       .fifo_size = SST_FIFO_SIZE,
+};
+
+static struct sst_dev_stream_map dpcm_strm_map[] = {
+       {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */
+       {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0},
+       {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0},
+       {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
+};
+
+static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+
+       return sst_send_pipe_gains(dai, stream, mute);
+}
+
+/* helper functions */
+void sst_set_stream_status(struct sst_runtime_stream *stream,
+                                       int state)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&stream->status_lock, flags);
+       stream->stream_status = state;
+       spin_unlock_irqrestore(&stream->status_lock, flags);
+}
+
+static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
+{
+       int state;
+       unsigned long flags;
+
+       spin_lock_irqsave(&stream->status_lock, flags);
+       state = stream->stream_status;
+       spin_unlock_irqrestore(&stream->status_lock, flags);
+       return state;
+}
+
+static void sst_fill_alloc_params(struct snd_pcm_substream *substream,
+                               struct snd_sst_alloc_params_ext *alloc_param)
+{
+       unsigned int channels;
+       snd_pcm_uframes_t period_size;
+       ssize_t periodbytes;
+       ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+       u32 buffer_addr = virt_to_phys(substream->dma_buffer.area);
+
+       channels = substream->runtime->channels;
+       period_size = substream->runtime->period_size;
+       periodbytes = samples_to_bytes(substream->runtime, period_size);
+       alloc_param->ring_buf_info[0].addr = buffer_addr;
+       alloc_param->ring_buf_info[0].size = buffer_bytes;
+       alloc_param->sg_count = 1;
+       alloc_param->reserved = 0;
+       alloc_param->frag_size = periodbytes * channels;
+
+}
+static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
+                               struct snd_sst_stream_params *param)
+{
+       param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
+       param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
+       param->uc.pcm_params.sfreq = substream->runtime->rate;
+
+       /* PCM stream via ALSA interface */
+       param->uc.pcm_params.use_offload_path = 0;
+       param->uc.pcm_params.reserved2 = 0;
+       memset(param->uc.pcm_params.channel_map, 0, sizeof(u8));
+
+}
+
+static int sst_get_stream_mapping(int dev, int sdev, int dir,
+       struct sst_dev_stream_map *map, int size)
+{
+       int i;
+
+       if (map == NULL)
+               return -EINVAL;
+
+
+       /* index 0 is not used in stream map */
+       for (i = 1; i < size; i++) {
+               if ((map[i].dev_num == dev) && (map[i].direction == dir))
+                       return i;
+       }
+       return 0;
+}
+
+int sst_fill_stream_params(void *substream,
+       const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress)
+{
+       int map_size;
+       int index;
+       struct sst_dev_stream_map *map;
+       struct snd_pcm_substream *pstream = NULL;
+       struct snd_compr_stream *cstream = NULL;
+
+       map = ctx->pdata->pdev_strm_map;
+       map_size = ctx->pdata->strm_map_size;
+
+       if (is_compress == true)
+               cstream = (struct snd_compr_stream *)substream;
+       else
+               pstream = (struct snd_pcm_substream *)substream;
+
+       str_params->stream_type = SST_STREAM_TYPE_MUSIC;
+
+       /* For pcm streams */
+       if (pstream) {
+               index = sst_get_stream_mapping(pstream->pcm->device,
+                                         pstream->number, pstream->stream,
+                                         map, map_size);
+               if (index <= 0)
+                       return -EINVAL;
+
+               str_params->stream_id = index;
+               str_params->device_type = map[index].device_id;
+               str_params->task = map[index].task_id;
+
+               str_params->ops = (u8)pstream->stream;
+       }
+
+       if (cstream) {
+               index = sst_get_stream_mapping(cstream->device->device,
+                                              0, cstream->direction,
+                                              map, map_size);
+               if (index <= 0)
+                       return -EINVAL;
+               str_params->stream_id = index;
+               str_params->device_type = map[index].device_id;
+               str_params->task = map[index].task_id;
+
+               str_params->ops = (u8)cstream->direction;
+       }
+       return 0;
+}
+
+static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct sst_runtime_stream *stream =
+                       substream->runtime->private_data;
+       struct snd_sst_stream_params param = {{{0,},},};
+       struct snd_sst_params str_params = {0};
+       struct snd_sst_alloc_params_ext alloc_params = {0};
+       int ret_val = 0;
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
+
+       /* set codec params and inform SST driver the same */
+       sst_fill_pcm_params(substream, &param);
+       sst_fill_alloc_params(substream, &alloc_params);
+       substream->runtime->dma_area = substream->dma_buffer.area;
+       str_params.sparams = param;
+       str_params.aparams = alloc_params;
+       str_params.codec = SST_CODEC_TYPE_PCM;
+
+       /* fill the device type and stream id to pass to SST driver */
+       ret_val = sst_fill_stream_params(substream, ctx, &str_params, false);
+       if (ret_val < 0)
+               return ret_val;
+
+       stream->stream_info.str_id = str_params.stream_id;
+
+       ret_val = stream->ops->open(sst->dev, &str_params);
+       if (ret_val <= 0)
+               return ret_val;
+
+
+       return ret_val;
+}
+
+static void sst_period_elapsed(void *arg)
+{
+       struct snd_pcm_substream *substream = arg;
+       struct sst_runtime_stream *stream;
+       int status;
+
+       if (!substream || !substream->runtime)
+               return;
+       stream = substream->runtime->private_data;
+       if (!stream)
+               return;
+       status = sst_get_stream_status(stream);
+       if (status != SST_PLATFORM_RUNNING)
+               return;
+       snd_pcm_period_elapsed(substream);
+}
+
+static int sst_platform_init_stream(struct snd_pcm_substream *substream)
+{
+       struct sst_runtime_stream *stream =
+                       substream->runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int ret_val;
+
+       dev_dbg(rtd->dev, "setting buffer ptr param\n");
+       sst_set_stream_status(stream, SST_PLATFORM_INIT);
+       stream->stream_info.period_elapsed = sst_period_elapsed;
+       stream->stream_info.arg = substream;
+       stream->stream_info.buffer_ptr = 0;
+       stream->stream_info.sfreq = substream->runtime->rate;
+       ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
+       if (ret_val)
+               dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
+       return ret_val;
+
+}
+
+static int power_up_sst(struct sst_runtime_stream *stream)
+{
+       return stream->ops->power(sst->dev, true);
+}
+
+static void power_down_sst(struct sst_runtime_stream *stream)
+{
+       stream->ops->power(sst->dev, false);
+}
+
+static int sst_media_open(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       int ret_val = 0;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sst_runtime_stream *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return -ENOMEM;
+       spin_lock_init(&stream->status_lock);
+
+       /* get the sst ops */
+       mutex_lock(&sst_lock);
+       if (!sst ||
+           !try_module_get(sst->dev->driver->owner)) {
+               dev_err(dai->dev, "no device available to run\n");
+               ret_val = -ENODEV;
+               goto out_ops;
+       }
+       stream->ops = sst->ops;
+       mutex_unlock(&sst_lock);
+
+       stream->stream_info.str_id = 0;
+
+       stream->stream_info.arg = substream;
+       /* allocate memory for SST API set */
+       runtime->private_data = stream;
+
+       ret_val = power_up_sst(stream);
+       if (ret_val < 0)
+               return ret_val;
+
+       /* Make sure, that the period size is always even */
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                          SNDRV_PCM_HW_PARAM_PERIODS, 2);
+
+       return snd_pcm_hw_constraint_integer(runtime,
+                        SNDRV_PCM_HW_PARAM_PERIODS);
+out_ops:
+       kfree(stream);
+       mutex_unlock(&sst_lock);
+       return ret_val;
+}
+
+static void sst_media_close(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val = 0, str_id;
+
+       stream = substream->runtime->private_data;
+       power_down_sst(stream);
+
+       str_id = stream->stream_info.str_id;
+       if (str_id)
+               ret_val = stream->ops->close(sst->dev, str_id);
+       module_put(sst->dev->driver->owner);
+       kfree(stream);
+}
+
+static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
+                                              struct snd_pcm_substream *substream)
+{
+       struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
+       struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
+       struct sst_runtime_stream *stream =
+                       substream->runtime->private_data;
+       u32 str_id = stream->stream_info.str_id;
+       unsigned int pipe_id;
+
+       pipe_id = map[str_id].device_id;
+
+       dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
+                       pipe_id, str_id);
+       return pipe_id;
+}
+
+static int sst_media_prepare(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val = 0, str_id;
+
+       stream = substream->runtime->private_data;
+       str_id = stream->stream_info.str_id;
+       if (stream->stream_info.str_id) {
+               ret_val = stream->ops->stream_drop(sst->dev, str_id);
+               return ret_val;
+       }
+
+       ret_val = sst_platform_alloc_stream(substream, dai);
+       if (ret_val <= 0)
+               return ret_val;
+       snprintf(substream->pcm->id, sizeof(substream->pcm->id),
+                       "%d", stream->stream_info.str_id);
+
+       ret_val = sst_platform_init_stream(substream);
+       if (ret_val)
+               return ret_val;
+       substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
+       return ret_val;
+}
+
+static int sst_media_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+       return 0;
+}
+
+static int sst_media_hw_free(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int sst_enable_ssp(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
+{
+       int ret = 0;
+
+       if (!dai->active) {
+               ret = sst_handle_vb_timer(dai, true);
+               if (ret)
+                       return ret;
+               ret = send_ssp_cmd(dai, dai->name, 1);
+       }
+       return ret;
+}
+
+static void sst_disable_ssp(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
+{
+       if (!dai->active) {
+               send_ssp_cmd(dai, dai->name, 0);
+               sst_handle_vb_timer(dai, false);
+       }
+}
+
+static struct snd_soc_dai_ops sst_media_dai_ops = {
+       .startup = sst_media_open,
+       .shutdown = sst_media_close,
+       .prepare = sst_media_prepare,
+       .hw_params = sst_media_hw_params,
+       .hw_free = sst_media_hw_free,
+       .mute_stream = sst_media_digital_mute,
+};
+
+static struct snd_soc_dai_ops sst_compr_dai_ops = {
+       .mute_stream = sst_media_digital_mute,
+};
+
+static struct snd_soc_dai_ops sst_be_dai_ops = {
+       .startup = sst_enable_ssp,
+       .shutdown = sst_disable_ssp,
+};
+
+static struct snd_soc_dai_driver sst_platform_dai[] = {
+{
+       .name = "media-cpu-dai",
+       .ops = &sst_media_dai_ops,
+       .playback = {
+               .stream_name = "Headset Playback",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "Headset Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+{
+       .name = "compress-cpu-dai",
+       .compress_dai = 1,
+       .ops = &sst_compr_dai_ops,
+       .playback = {
+               .stream_name = "Compress Playback",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+/* BE CPU  Dais */
+{
+       .name = "ssp0-port",
+       .ops = &sst_be_dai_ops,
+       .playback = {
+               .stream_name = "ssp0 Tx",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "ssp0 Rx",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+{
+       .name = "ssp1-port",
+       .ops = &sst_be_dai_ops,
+       .playback = {
+               .stream_name = "ssp1 Tx",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "ssp1 Rx",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+{
+       .name = "ssp2-port",
+       .ops = &sst_be_dai_ops,
+       .playback = {
+               .stream_name = "ssp2 Tx",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "ssp2 Rx",
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+};
+
+static int sst_platform_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime;
+
+       if (substream->pcm->internal)
+               return 0;
+
+       runtime = substream->runtime;
+       runtime->hw = sst_platform_pcm_hw;
+       return 0;
+}
+
+static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
+                                       int cmd)
+{
+       int ret_val = 0, str_id;
+       struct sst_runtime_stream *stream;
+       int status;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
+       if (substream->pcm->internal)
+               return 0;
+       stream = substream->runtime->private_data;
+       str_id = stream->stream_info.str_id;
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               dev_dbg(rtd->dev, "sst: Trigger Start\n");
+               status = SST_PLATFORM_RUNNING;
+               stream->stream_info.arg = substream;
+               ret_val = stream->ops->stream_start(sst->dev, str_id);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               dev_dbg(rtd->dev, "sst: in stop\n");
+               status = SST_PLATFORM_DROPPED;
+               ret_val = stream->ops->stream_drop(sst->dev, str_id);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               dev_dbg(rtd->dev, "sst: in pause\n");
+               status = SST_PLATFORM_PAUSED;
+               ret_val = stream->ops->stream_pause(sst->dev, str_id);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               dev_dbg(rtd->dev, "sst: in pause release\n");
+               status = SST_PLATFORM_RUNNING;
+               ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!ret_val)
+               sst_set_stream_status(stream, status);
+
+       return ret_val;
+}
+
+
+static snd_pcm_uframes_t sst_platform_pcm_pointer
+                       (struct snd_pcm_substream *substream)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val, status;
+       struct pcm_stream_info *str_info;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       stream = substream->runtime->private_data;
+       status = sst_get_stream_status(stream);
+       if (status == SST_PLATFORM_INIT)
+               return 0;
+       str_info = &stream->stream_info;
+       ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
+       if (ret_val) {
+               dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
+               return ret_val;
+       }
+       substream->runtime->delay = str_info->pcm_delay;
+       return str_info->buffer_ptr;
+}
+
+static struct snd_pcm_ops sst_platform_ops = {
+       .open = sst_platform_open,
+       .ioctl = snd_pcm_lib_ioctl,
+       .trigger = sst_platform_pcm_trigger,
+       .pointer = sst_platform_pcm_pointer,
+};
+
+static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
+       int retval = 0;
+
+       if (dai->driver->playback.channels_min ||
+                       dai->driver->capture.channels_min) {
+               retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
+                       SNDRV_DMA_TYPE_CONTINUOUS,
+                       snd_dma_continuous_data(GFP_DMA),
+                       SST_MIN_BUFFER, SST_MAX_BUFFER);
+               if (retval) {
+                       dev_err(rtd->dev, "dma buffer allocationf fail\n");
+                       return retval;
+               }
+       }
+       return retval;
+}
+
+static int sst_soc_probe(struct snd_soc_platform *platform)
+{
+       struct sst_data *drv = dev_get_drvdata(platform->dev);
+
+       drv->soc_card = platform->component.card;
+       return sst_dsp_init_v2_dpcm(platform);
+}
+
+static struct snd_soc_platform_driver sst_soc_platform_drv  = {
+       .probe          = sst_soc_probe,
+       .ops            = &sst_platform_ops,
+       .compr_ops      = &sst_platform_compr_ops,
+       .pcm_new        = sst_pcm_new,
+};
+
+static const struct snd_soc_component_driver sst_component = {
+       .name           = "sst",
+};
+
+
+static int sst_platform_probe(struct platform_device *pdev)
+{
+       struct sst_data *drv;
+       int ret;
+       struct sst_platform_data *pdata;
+
+       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+       if (drv == NULL) {
+               return -ENOMEM;
+       }
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (pdata == NULL) {
+               return -ENOMEM;
+       }
+
+       pdata->pdev_strm_map = dpcm_strm_map;
+       pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map);
+       drv->pdata = pdata;
+       drv->pdev = pdev;
+       mutex_init(&drv->lock);
+       dev_set_drvdata(&pdev->dev, drv);
+
+       ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
+       if (ret) {
+               dev_err(&pdev->dev, "registering soc platform failed\n");
+               return ret;
+       }
+
+       ret = snd_soc_register_component(&pdev->dev, &sst_component,
+                               sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
+       if (ret) {
+               dev_err(&pdev->dev, "registering cpu dais failed\n");
+               snd_soc_unregister_platform(&pdev->dev);
+       }
+       return ret;
+}
+
+static int sst_platform_remove(struct platform_device *pdev)
+{
+
+       snd_soc_unregister_component(&pdev->dev);
+       snd_soc_unregister_platform(&pdev->dev);
+       dev_dbg(&pdev->dev, "sst_platform_remove success\n");
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int sst_soc_prepare(struct device *dev)
+{
+       struct sst_data *drv = dev_get_drvdata(dev);
+       int i;
+
+       /* suspend all pcms first */
+       snd_soc_suspend(drv->soc_card->dev);
+       snd_soc_poweroff(drv->soc_card->dev);
+
+       /* set the SSPs to idle */
+       for (i = 0; i < drv->soc_card->num_rtd; i++) {
+               struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+
+               if (dai->active) {
+                       send_ssp_cmd(dai, dai->name, 0);
+                       sst_handle_vb_timer(dai, false);
+               }
+       }
+
+       return 0;
+}
+
+static void sst_soc_complete(struct device *dev)
+{
+       struct sst_data *drv = dev_get_drvdata(dev);
+       int i;
+
+       /* restart SSPs */
+       for (i = 0; i < drv->soc_card->num_rtd; i++) {
+               struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+
+               if (dai->active) {
+                       sst_handle_vb_timer(dai, true);
+                       send_ssp_cmd(dai, dai->name, 1);
+               }
+       }
+       snd_soc_resume(drv->soc_card->dev);
+}
+
+#else
+
+#define sst_soc_prepare NULL
+#define sst_soc_complete NULL
+
+#endif
+
+
+static const struct dev_pm_ops sst_platform_pm = {
+       .prepare        = sst_soc_prepare,
+       .complete       = sst_soc_complete,
+};
+
+static struct platform_driver sst_platform_driver = {
+       .driver         = {
+               .name           = "sst-mfld-platform",
+               .pm             = &sst_platform_pm,
+       },
+       .probe          = sst_platform_probe,
+       .remove         = sst_platform_remove,
+};
+
+module_platform_driver(sst_platform_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sst-mfld-platform");
diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h
new file mode 100644 (file)
index 0000000..9094314
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ *  sst_mfld_platform.h - Intel MID Platform driver header file
+ *
+ *  Copyright (C) 2010 Intel Corp
+ *  Author: Vinod Koul <vinod.koul@intel.com>
+ *  Author: Harsha Priya <priya.harsha@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef __SST_PLATFORMDRV_H__
+#define __SST_PLATFORMDRV_H__
+
+#include "sst-mfld-dsp.h"
+
+extern struct sst_device *sst;
+
+#define SST_MONO               1
+#define SST_STEREO             2
+#define SST_MAX_CAP            5
+
+#define SST_MAX_BUFFER         (800*1024)
+#define SST_MIN_BUFFER         (800*1024)
+#define SST_MIN_PERIOD_BYTES   32
+#define SST_MAX_PERIOD_BYTES   SST_MAX_BUFFER
+#define SST_MIN_PERIODS                2
+#define SST_MAX_PERIODS                (1024*2)
+#define SST_FIFO_SIZE          0
+
+struct pcm_stream_info {
+       int str_id;
+       void *arg;
+       void (*period_elapsed) (void *arg);
+       unsigned long long buffer_ptr;
+       unsigned long long pcm_delay;
+       int sfreq;
+};
+
+enum sst_drv_status {
+       SST_PLATFORM_INIT = 1,
+       SST_PLATFORM_STARTED,
+       SST_PLATFORM_RUNNING,
+       SST_PLATFORM_PAUSED,
+       SST_PLATFORM_DROPPED,
+};
+
+enum sst_stream_ops {
+       STREAM_OPS_PLAYBACK = 0,
+       STREAM_OPS_CAPTURE,
+};
+
+enum sst_audio_device_type {
+       SND_SST_DEVICE_HEADSET = 1,
+       SND_SST_DEVICE_IHF,
+       SND_SST_DEVICE_VIBRA,
+       SND_SST_DEVICE_HAPTIC,
+       SND_SST_DEVICE_CAPTURE,
+       SND_SST_DEVICE_COMPRESS,
+};
+
+/* PCM Parameters */
+struct sst_pcm_params {
+       u16 codec;      /* codec type */
+       u8 num_chan;    /* 1=Mono, 2=Stereo */
+       u8 pcm_wd_sz;   /* 16/24 - bit*/
+       u32 reserved;   /* Bitrate in bits per second */
+       u32 sfreq;      /* Sampling rate in Hz */
+       u32 ring_buffer_size;
+       u32 period_count;       /* period elapsed in samples*/
+       u32 ring_buffer_addr;
+};
+
+struct sst_stream_params {
+       u32 result;
+       u32 stream_id;
+       u8 codec;
+       u8 ops;
+       u8 stream_type;
+       u8 device_type;
+       struct sst_pcm_params sparams;
+};
+
+struct sst_compress_cb {
+       void *param;
+       void (*compr_cb)(void *param);
+       void *drain_cb_param;
+       void (*drain_notify)(void *param);
+};
+
+struct compress_sst_ops {
+       const char *name;
+       int (*open)(struct device *dev,
+               struct snd_sst_params *str_params, struct sst_compress_cb *cb);
+       int (*stream_start)(struct device *dev, unsigned int str_id);
+       int (*stream_drop)(struct device *dev, unsigned int str_id);
+       int (*stream_drain)(struct device *dev, unsigned int str_id);
+       int (*stream_partial_drain)(struct device *dev, unsigned int str_id);
+       int (*stream_pause)(struct device *dev, unsigned int str_id);
+       int (*stream_pause_release)(struct device *dev, unsigned int str_id);
+
+       int (*tstamp)(struct device *dev, unsigned int str_id,
+                       struct snd_compr_tstamp *tstamp);
+       int (*ack)(struct device *dev, unsigned int str_id,
+                       unsigned long bytes);
+       int (*close)(struct device *dev, unsigned int str_id);
+       int (*get_caps)(struct snd_compr_caps *caps);
+       int (*get_codec_caps)(struct snd_compr_codec_caps *codec);
+       int (*set_metadata)(struct device *dev, unsigned int str_id,
+                       struct snd_compr_metadata *mdata);
+       int (*power)(struct device *dev, bool state);
+};
+
+struct sst_ops {
+       int (*open)(struct device *dev, struct snd_sst_params *str_param);
+       int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info);
+       int (*stream_start)(struct device *dev, int str_id);
+       int (*stream_drop)(struct device *dev, int str_id);
+       int (*stream_pause)(struct device *dev, int str_id);
+       int (*stream_pause_release)(struct device *dev, int str_id);
+       int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info);
+       int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes);
+       int (*close)(struct device *dev, unsigned int str_id);
+       int (*power)(struct device *dev, bool state);
+};
+
+struct sst_runtime_stream {
+       int     stream_status;
+       unsigned int id;
+       size_t bytes_written;
+       struct pcm_stream_info stream_info;
+       struct sst_ops *ops;
+       struct compress_sst_ops *compr_ops;
+       spinlock_t      status_lock;
+};
+
+struct sst_device {
+       char *name;
+       struct device *dev;
+       struct sst_ops *ops;
+       struct platform_device *pdev;
+       struct compress_sst_ops *compr_ops;
+};
+
+struct sst_data;
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform);
+int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute);
+int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable);
+int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable);
+
+void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
+int sst_fill_stream_params(void *substream, const struct sst_data *ctx,
+                          struct snd_sst_params *str_params, bool is_compress);
+
+struct sst_algo_int_control_v2 {
+       struct soc_mixer_control mc;
+       u16 module_id; /* module identifieer */
+       u16 pipe_id; /* location info: pipe_id + instance_id */
+       u16 instance_id;
+       unsigned int value; /* Value received is stored here */
+};
+struct sst_data {
+       struct platform_device *pdev;
+       struct sst_platform_data *pdata;
+       struct snd_sst_bytes_v2 *byte_stream;
+       struct mutex lock;
+       struct snd_soc_card *soc_card;
+};
+int sst_register_dsp(struct sst_device *sst);
+int sst_unregister_dsp(struct sst_device *sst);
+#endif
diff --git a/sound/soc/intel/atom/sst/Makefile b/sound/soc/intel/atom/sst/Makefile
new file mode 100644 (file)
index 0000000..fd21726
--- /dev/null
@@ -0,0 +1,7 @@
+snd-intel-sst-core-objs := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o
+snd-intel-sst-pci-objs += sst_pci.o
+snd-intel-sst-acpi-objs += sst_acpi.o
+
+obj-$(CONFIG_SND_SST_IPC) += snd-intel-sst-core.o
+obj-$(CONFIG_SND_SST_IPC_PCI) += snd-intel-sst-pci.o
+obj-$(CONFIG_SND_SST_IPC_ACPI) += snd-intel-sst-acpi.o
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c
new file mode 100644 (file)
index 0000000..96c2e42
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ *  sst.c - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-14      Intel Corp
+ *  Authors:   Vinod Koul <vinod.koul@intel.com>
+ *             Harsha Priya <priya.harsha@intel.com>
+ *             Dharageswari R <dharageswari.r@intel.com>
+ *             KP Jeeja <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/async.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../../common/sst-dsp.h"
+
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver");
+MODULE_LICENSE("GPL v2");
+
+static inline bool sst_is_process_reply(u32 msg_id)
+{
+       return ((msg_id & PROCESS_MSG) ? true : false);
+}
+
+static inline bool sst_validate_mailbox_size(unsigned int size)
+{
+       return ((size <= SST_MAILBOX_SIZE) ? true : false);
+}
+
+static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context)
+{
+       union interrupt_reg_mrfld isr;
+       union ipc_header_mrfld header;
+       union sst_imr_reg_mrfld imr;
+       struct ipc_post *msg = NULL;
+       unsigned int size = 0;
+       struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
+       irqreturn_t retval = IRQ_HANDLED;
+
+       /* Interrupt arrived, check src */
+       isr.full = sst_shim_read64(drv->shim, SST_ISRX);
+
+       if (isr.part.done_interrupt) {
+               /* Clear done bit */
+               spin_lock(&drv->ipc_spin_lock);
+               header.full = sst_shim_read64(drv->shim,
+                                       drv->ipc_reg.ipcx);
+               header.p.header_high.part.done = 0;
+               sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full);
+
+               /* write 1 to clear status register */;
+               isr.part.done_interrupt = 1;
+               sst_shim_write64(drv->shim, SST_ISRX, isr.full);
+               spin_unlock(&drv->ipc_spin_lock);
+
+               /* we can send more messages to DSP so trigger work */
+               queue_work(drv->post_msg_wq, &drv->ipc_post_msg_wq);
+               retval = IRQ_HANDLED;
+       }
+
+       if (isr.part.busy_interrupt) {
+               /* message from dsp so copy that */
+               spin_lock(&drv->ipc_spin_lock);
+               imr.full = sst_shim_read64(drv->shim, SST_IMRX);
+               imr.part.busy_interrupt = 1;
+               sst_shim_write64(drv->shim, SST_IMRX, imr.full);
+               spin_unlock(&drv->ipc_spin_lock);
+               header.full =  sst_shim_read64(drv->shim, drv->ipc_reg.ipcd);
+
+               if (sst_create_ipc_msg(&msg, header.p.header_high.part.large)) {
+                       drv->ops->clear_interrupt(drv);
+                       return IRQ_HANDLED;
+               }
+
+               if (header.p.header_high.part.large) {
+                       size = header.p.header_low_payload;
+                       if (sst_validate_mailbox_size(size)) {
+                               memcpy_fromio(msg->mailbox_data,
+                                       drv->mailbox + drv->mailbox_recv_offset, size);
+                       } else {
+                               dev_err(drv->dev,
+                                       "Mailbox not copied, payload size is: %u\n", size);
+                               header.p.header_low_payload = 0;
+                       }
+               }
+
+               msg->mrfld_header = header;
+               msg->is_process_reply =
+                       sst_is_process_reply(header.p.header_high.part.msg_id);
+               spin_lock(&drv->rx_msg_lock);
+               list_add_tail(&msg->node, &drv->rx_list);
+               spin_unlock(&drv->rx_msg_lock);
+               drv->ops->clear_interrupt(drv);
+               retval = IRQ_WAKE_THREAD;
+       }
+       return retval;
+}
+
+static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context)
+{
+       struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
+       struct ipc_post *__msg, *msg = NULL;
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
+       if (list_empty(&drv->rx_list)) {
+               spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
+               return IRQ_HANDLED;
+       }
+
+       list_for_each_entry_safe(msg, __msg, &drv->rx_list, node) {
+               list_del(&msg->node);
+               spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
+               if (msg->is_process_reply)
+                       drv->ops->process_message(msg);
+               else
+                       drv->ops->process_reply(drv, msg);
+
+               if (msg->is_large)
+                       kfree(msg->mailbox_data);
+               kfree(msg);
+               spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
+       }
+       spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
+       return IRQ_HANDLED;
+}
+
+static int sst_save_dsp_context_v2(struct intel_sst_drv *sst)
+{
+       int ret = 0;
+
+       ret = sst_prepare_and_post_msg(sst, SST_TASK_ID_MEDIA, IPC_CMD,
+                       IPC_PREP_D3, PIPE_RSVD, 0, NULL, NULL,
+                       true, true, false, true);
+
+       if (ret < 0) {
+               dev_err(sst->dev, "not suspending FW!!, Err: %d\n", ret);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+
+static struct intel_sst_ops mrfld_ops = {
+       .interrupt = intel_sst_interrupt_mrfld,
+       .irq_thread = intel_sst_irq_thread_mrfld,
+       .clear_interrupt = intel_sst_clear_intr_mrfld,
+       .start = sst_start_mrfld,
+       .reset = intel_sst_reset_dsp_mrfld,
+       .post_message = sst_post_message_mrfld,
+       .process_reply = sst_process_reply_mrfld,
+       .save_dsp_context =  sst_save_dsp_context_v2,
+       .alloc_stream = sst_alloc_stream_mrfld,
+       .post_download = sst_post_download_mrfld,
+};
+
+int sst_driver_ops(struct intel_sst_drv *sst)
+{
+
+       switch (sst->dev_id) {
+       case SST_MRFLD_PCI_ID:
+       case SST_BYT_ACPI_ID:
+       case SST_CHV_ACPI_ID:
+               sst->tstamp = SST_TIME_STAMP_MRFLD;
+               sst->ops = &mrfld_ops;
+               return 0;
+
+       default:
+               dev_err(sst->dev,
+                       "SST Driver capablities missing for dev_id: %x", sst->dev_id);
+               return -EINVAL;
+       };
+}
+
+void sst_process_pending_msg(struct work_struct *work)
+{
+       struct intel_sst_drv *ctx = container_of(work,
+                       struct intel_sst_drv, ipc_post_msg_wq);
+
+       ctx->ops->post_message(ctx, NULL, false);
+}
+
+static int sst_workqueue_init(struct intel_sst_drv *ctx)
+{
+       INIT_LIST_HEAD(&ctx->memcpy_list);
+       INIT_LIST_HEAD(&ctx->rx_list);
+       INIT_LIST_HEAD(&ctx->ipc_dispatch_list);
+       INIT_LIST_HEAD(&ctx->block_list);
+       INIT_WORK(&ctx->ipc_post_msg_wq, sst_process_pending_msg);
+       init_waitqueue_head(&ctx->wait_queue);
+
+       ctx->post_msg_wq =
+               create_singlethread_workqueue("sst_post_msg_wq");
+       if (!ctx->post_msg_wq)
+               return -EBUSY;
+       return 0;
+}
+
+static void sst_init_locks(struct intel_sst_drv *ctx)
+{
+       mutex_init(&ctx->sst_lock);
+       spin_lock_init(&ctx->rx_msg_lock);
+       spin_lock_init(&ctx->ipc_spin_lock);
+       spin_lock_init(&ctx->block_lock);
+}
+
+int sst_alloc_drv_context(struct intel_sst_drv **ctx,
+               struct device *dev, unsigned int dev_id)
+{
+       *ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL);
+       if (!(*ctx))
+               return -ENOMEM;
+
+       (*ctx)->dev = dev;
+       (*ctx)->dev_id = dev_id;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_alloc_drv_context);
+
+int sst_context_init(struct intel_sst_drv *ctx)
+{
+       int ret = 0, i;
+
+       if (!ctx->pdata)
+               return -EINVAL;
+
+       if (!ctx->pdata->probe_data)
+               return -EINVAL;
+
+       memcpy(&ctx->info, ctx->pdata->probe_data, sizeof(ctx->info));
+
+       ret = sst_driver_ops(ctx);
+       if (ret != 0)
+               return -EINVAL;
+
+       sst_init_locks(ctx);
+       sst_set_fw_state_locked(ctx, SST_RESET);
+
+       /* pvt_id 0 reserved for async messages */
+       ctx->pvt_id = 1;
+       ctx->stream_cnt = 0;
+       ctx->fw_in_mem = NULL;
+       /* we use memcpy, so set to 0 */
+       ctx->use_dma = 0;
+       ctx->use_lli = 0;
+
+       if (sst_workqueue_init(ctx))
+               return -EINVAL;
+
+       ctx->mailbox_recv_offset = ctx->pdata->ipc_info->mbox_recv_off;
+       ctx->ipc_reg.ipcx = SST_IPCX + ctx->pdata->ipc_info->ipc_offset;
+       ctx->ipc_reg.ipcd = SST_IPCD + ctx->pdata->ipc_info->ipc_offset;
+
+       dev_info(ctx->dev, "Got drv data max stream %d\n",
+                               ctx->info.max_streams);
+
+       for (i = 1; i <= ctx->info.max_streams; i++) {
+               struct stream_info *stream = &ctx->streams[i];
+
+               memset(stream, 0, sizeof(*stream));
+               stream->pipe_id = PIPE_RSVD;
+               mutex_init(&stream->lock);
+       }
+
+       /* Register the ISR */
+       ret = devm_request_threaded_irq(ctx->dev, ctx->irq_num, ctx->ops->interrupt,
+                                       ctx->ops->irq_thread, 0, SST_DRV_NAME,
+                                       ctx);
+       if (ret)
+               goto do_free_mem;
+
+       dev_dbg(ctx->dev, "Registered IRQ %#x\n", ctx->irq_num);
+
+       /* default intr are unmasked so set this as masked */
+       sst_shim_write64(ctx->shim, SST_IMRX, 0xFFFF0038);
+
+       ctx->qos = devm_kzalloc(ctx->dev,
+               sizeof(struct pm_qos_request), GFP_KERNEL);
+       if (!ctx->qos) {
+               ret = -ENOMEM;
+               goto do_free_mem;
+       }
+       pm_qos_add_request(ctx->qos, PM_QOS_CPU_DMA_LATENCY,
+                               PM_QOS_DEFAULT_VALUE);
+
+       dev_dbg(ctx->dev, "Requesting FW %s now...\n", ctx->firmware_name);
+       ret = request_firmware_nowait(THIS_MODULE, true, ctx->firmware_name,
+                                     ctx->dev, GFP_KERNEL, ctx, sst_firmware_load_cb);
+       if (ret) {
+               dev_err(ctx->dev, "Firmware download failed:%d\n", ret);
+               goto do_free_mem;
+       }
+       sst_register(ctx->dev);
+       return 0;
+
+do_free_mem:
+       destroy_workqueue(ctx->post_msg_wq);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_context_init);
+
+void sst_context_cleanup(struct intel_sst_drv *ctx)
+{
+       pm_runtime_get_noresume(ctx->dev);
+       pm_runtime_disable(ctx->dev);
+       sst_unregister(ctx->dev);
+       sst_set_fw_state_locked(ctx, SST_SHUTDOWN);
+       flush_scheduled_work();
+       destroy_workqueue(ctx->post_msg_wq);
+       pm_qos_remove_request(ctx->qos);
+       kfree(ctx->fw_sg_list.src);
+       kfree(ctx->fw_sg_list.dst);
+       ctx->fw_sg_list.list_len = 0;
+       kfree(ctx->fw_in_mem);
+       ctx->fw_in_mem = NULL;
+       sst_memcpy_free_resources(ctx);
+       ctx = NULL;
+}
+EXPORT_SYMBOL_GPL(sst_context_cleanup);
+
+static inline void sst_save_shim64(struct intel_sst_drv *ctx,
+                           void __iomem *shim,
+                           struct sst_shim_regs64 *shim_regs)
+{
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
+
+       shim_regs->imrx = sst_shim_read64(shim, SST_IMRX);
+       shim_regs->csr = sst_shim_read64(shim, SST_CSR);
+
+
+       spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
+}
+
+static inline void sst_restore_shim64(struct intel_sst_drv *ctx,
+                                     void __iomem *shim,
+                                     struct sst_shim_regs64 *shim_regs)
+{
+       unsigned long irq_flags;
+
+       /*
+        * we only need to restore IMRX for this case, rest will be
+        * initialize by FW or driver when firmware is loaded
+        */
+       spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
+       sst_shim_write64(shim, SST_IMRX, shim_regs->imrx),
+       sst_shim_write64(shim, SST_CSR, shim_regs->csr),
+       spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
+}
+
+void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
+{
+       pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY);
+       pm_runtime_use_autosuspend(ctx->dev);
+       /*
+        * For acpi devices, the actual physical device state is
+        * initially active. So change the state to active before
+        * enabling the pm
+        */
+
+       if (!acpi_disabled)
+               pm_runtime_set_active(ctx->dev);
+
+       pm_runtime_enable(ctx->dev);
+
+       if (acpi_disabled)
+               pm_runtime_set_active(ctx->dev);
+       else
+               pm_runtime_put_noidle(ctx->dev);
+
+       sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
+}
+EXPORT_SYMBOL_GPL(sst_configure_runtime_pm);
+
+static int intel_sst_runtime_suspend(struct device *dev)
+{
+       int ret = 0;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (ctx->sst_state == SST_RESET) {
+               dev_dbg(dev, "LPE is already in RESET state, No action\n");
+               return 0;
+       }
+       /* save fw context */
+       if (ctx->ops->save_dsp_context(ctx))
+               return -EBUSY;
+
+       /* Move the SST state to Reset */
+       sst_set_fw_state_locked(ctx, SST_RESET);
+
+       synchronize_irq(ctx->irq_num);
+       flush_workqueue(ctx->post_msg_wq);
+
+       ctx->ops->reset(ctx);
+       /* save the shim registers because PMC doesn't save state */
+       sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
+
+       return ret;
+}
+
+static int intel_sst_suspend(struct device *dev)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+       struct sst_fw_save *fw_save;
+       int i, ret = 0;
+
+       /* check first if we are already in SW reset */
+       if (ctx->sst_state == SST_RESET)
+               return 0;
+
+       /*
+        * check if any stream is active and running
+        * they should already by suspend by soc_suspend
+        */
+       for (i = 1; i <= ctx->info.max_streams; i++) {
+               struct stream_info *stream = &ctx->streams[i];
+
+               if (stream->status == STREAM_RUNNING) {
+                       dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
+                       return -EBUSY;
+               }
+       }
+       synchronize_irq(ctx->irq_num);
+       flush_workqueue(ctx->post_msg_wq);
+
+       /* Move the SST state to Reset */
+       sst_set_fw_state_locked(ctx, SST_RESET);
+
+       /* tell DSP we are suspending */
+       if (ctx->ops->save_dsp_context(ctx))
+               return -EBUSY;
+
+       /* save the memories */
+       fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
+       if (!fw_save)
+               return -ENOMEM;
+       fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
+       if (!fw_save->iram) {
+               ret = -ENOMEM;
+               goto iram;
+       }
+       fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
+       if (!fw_save->dram) {
+               ret = -ENOMEM;
+               goto dram;
+       }
+       fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
+       if (!fw_save->sram) {
+               ret = -ENOMEM;
+               goto sram;
+       }
+
+       fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
+       if (!fw_save->ddr) {
+               ret = -ENOMEM;
+               goto ddr;
+       }
+
+       memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base);
+       memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base);
+       memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE);
+       memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base);
+
+       ctx->fw_save = fw_save;
+       ctx->ops->reset(ctx);
+       return 0;
+ddr:
+       kfree(fw_save->sram);
+sram:
+       kfree(fw_save->dram);
+dram:
+       kfree(fw_save->iram);
+iram:
+       kfree(fw_save);
+       return ret;
+}
+
+static int intel_sst_resume(struct device *dev)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+       struct sst_fw_save *fw_save = ctx->fw_save;
+       int ret = 0;
+       struct sst_block *block;
+
+       if (!fw_save)
+               return 0;
+
+       sst_set_fw_state_locked(ctx, SST_FW_LOADING);
+
+       /* we have to restore the memory saved */
+       ctx->ops->reset(ctx);
+
+       ctx->fw_save = NULL;
+
+       memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base);
+       memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base);
+       memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE);
+       memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base);
+
+       kfree(fw_save->sram);
+       kfree(fw_save->dram);
+       kfree(fw_save->iram);
+       kfree(fw_save->ddr);
+       kfree(fw_save);
+
+       block = sst_create_block(ctx, 0, FW_DWNL_ID);
+       if (block == NULL)
+               return -ENOMEM;
+
+
+       /* start and wait for ack */
+       ctx->ops->start(ctx);
+       ret = sst_wait_timeout(ctx, block);
+       if (ret) {
+               dev_err(ctx->dev, "fw download failed %d\n", ret);
+               /* FW download failed due to timeout */
+               ret = -EBUSY;
+
+       } else {
+               sst_set_fw_state_locked(ctx, SST_FW_RUNNING);
+       }
+
+       sst_free_block(ctx, block);
+       return ret;
+}
+
+const struct dev_pm_ops intel_sst_pm = {
+       .suspend = intel_sst_suspend,
+       .resume = intel_sst_resume,
+       .runtime_suspend = intel_sst_runtime_suspend,
+};
+EXPORT_SYMBOL_GPL(intel_sst_pm);
diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h
new file mode 100644 (file)
index 0000000..3f49386
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ *  sst.h - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-14 Intel Corporation
+ *  Authors:   Vinod Koul <vinod.koul@intel.com>
+ *             Harsha Priya <priya.harsha@intel.com>
+ *             Dharageswari R <dharageswari.r@intel.com>
+ *             KP Jeeja <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  Common private declarations for SST
+ */
+#ifndef __SST_H__
+#define __SST_H__
+
+#include <linux/firmware.h>
+
+/* driver names */
+#define SST_DRV_NAME "intel_sst_driver"
+#define SST_MRFLD_PCI_ID 0x119A
+#define SST_BYT_ACPI_ID        0x80860F28
+#define SST_CHV_ACPI_ID        0x808622A8
+
+#define SST_SUSPEND_DELAY 2000
+#define FW_CONTEXT_MEM (64*1024)
+#define SST_ICCM_BOUNDARY 4
+#define SST_CONFIG_SSP_SIGN 0x7ffe8001
+
+#define MRFLD_FW_VIRTUAL_BASE 0xC0000000
+#define MRFLD_FW_DDR_BASE_OFFSET 0x0
+#define MRFLD_FW_FEATURE_BASE_OFFSET 0x4
+#define MRFLD_FW_BSS_RESET_BIT 0
+
+extern const struct dev_pm_ops intel_sst_pm;
+enum sst_states {
+       SST_FW_LOADING = 1,
+       SST_FW_RUNNING,
+       SST_RESET,
+       SST_SHUTDOWN,
+};
+
+enum sst_algo_ops {
+       SST_SET_ALGO = 0,
+       SST_GET_ALGO = 1,
+};
+
+#define SST_BLOCK_TIMEOUT      1000
+
+#define FW_SIGNATURE_SIZE      4
+#define FW_NAME_SIZE           32
+
+/* stream states */
+enum sst_stream_states {
+       STREAM_UN_INIT  = 0,    /* Freed/Not used stream */
+       STREAM_RUNNING  = 1,    /* Running */
+       STREAM_PAUSED   = 2,    /* Paused stream */
+       STREAM_DECODE   = 3,    /* stream is in decoding only state */
+       STREAM_INIT     = 4,    /* stream init, waiting for data */
+       STREAM_RESET    = 5,    /* force reset on recovery */
+};
+
+enum sst_ram_type {
+       SST_IRAM        = 1,
+       SST_DRAM        = 2,
+       SST_DDR = 5,
+       SST_CUSTOM_INFO = 7,    /* consists of FW binary information */
+};
+
+/* SST shim registers to structure mapping */
+union interrupt_reg {
+       struct {
+               u64 done_interrupt:1;
+               u64 busy_interrupt:1;
+               u64 rsvd:62;
+       } part;
+       u64 full;
+};
+
+union sst_pisr_reg {
+       struct {
+               u32 pssp0:1;
+               u32 pssp1:1;
+               u32 rsvd0:3;
+               u32 dmac:1;
+               u32 rsvd1:26;
+       } part;
+       u32 full;
+};
+
+union sst_pimr_reg {
+       struct {
+               u32 ssp0:1;
+               u32 ssp1:1;
+               u32 rsvd0:3;
+               u32 dmac:1;
+               u32 rsvd1:10;
+               u32 ssp0_sc:1;
+               u32 ssp1_sc:1;
+               u32 rsvd2:3;
+               u32 dmac_sc:1;
+               u32 rsvd3:10;
+       } part;
+       u32 full;
+};
+
+union config_status_reg_mrfld {
+       struct {
+               u64 lpe_reset:1;
+               u64 lpe_reset_vector:1;
+               u64 runstall:1;
+               u64 pwaitmode:1;
+               u64 clk_sel:3;
+               u64 rsvd2:1;
+               u64 sst_clk:3;
+               u64 xt_snoop:1;
+               u64 rsvd3:4;
+               u64 clk_sel1:6;
+               u64 clk_enable:3;
+               u64 rsvd4:6;
+               u64 slim0baseclk:1;
+               u64 rsvd:32;
+       } part;
+       u64 full;
+};
+
+union interrupt_reg_mrfld {
+       struct {
+               u64 done_interrupt:1;
+               u64 busy_interrupt:1;
+               u64 rsvd:62;
+       } part;
+       u64 full;
+};
+
+union sst_imr_reg_mrfld {
+       struct {
+               u64 done_interrupt:1;
+               u64 busy_interrupt:1;
+               u64 rsvd:62;
+       } part;
+       u64 full;
+};
+
+/**
+ * struct sst_block - This structure is used to block a user/fw data call to another
+ * fw/user call
+ *
+ * @condition: condition for blocking check
+ * @ret_code: ret code when block is released
+ * @data: data ptr
+ * @size: size of data
+ * @on: block condition
+ * @msg_id: msg_id = msgid in mfld/ctp, mrfld = NULL
+ * @drv_id: str_id in mfld/ctp, = drv_id in mrfld
+ * @node: list head node
+ */
+struct sst_block {
+       bool    condition;
+       int     ret_code;
+       void    *data;
+       u32     size;
+       bool    on;
+       u32     msg_id;
+       u32     drv_id;
+       struct list_head node;
+};
+
+/**
+ * struct stream_info - structure that holds the stream information
+ *
+ * @status : stream current state
+ * @prev : stream prev state
+ * @ops : stream operation pb/cp/drm...
+ * @bufs: stream buffer list
+ * @lock : stream mutex for protecting state
+ * @pcm_substream : PCM substream
+ * @period_elapsed : PCM period elapsed callback
+ * @sfreq : stream sampling freq
+ * @str_type : stream type
+ * @cumm_bytes : cummulative bytes decoded
+ * @str_type : stream type
+ * @src : stream source
+ */
+struct stream_info {
+       unsigned int            status;
+       unsigned int            prev;
+       unsigned int            ops;
+       struct mutex            lock;
+
+       void                    *pcm_substream;
+       void (*period_elapsed)(void *pcm_substream);
+
+       unsigned int            sfreq;
+       u32                     cumm_bytes;
+
+       void                    *compr_cb_param;
+       void (*compr_cb)(void *compr_cb_param);
+
+       void                    *drain_cb_param;
+       void (*drain_notify)(void *drain_cb_param);
+
+       unsigned int            num_ch;
+       unsigned int            pipe_id;
+       unsigned int            str_id;
+       unsigned int            task_id;
+};
+
+#define SST_FW_SIGN "$SST"
+#define SST_FW_LIB_SIGN "$LIB"
+
+/**
+ * struct sst_fw_header - FW file headers
+ *
+ * @signature : FW signature
+ * @file_size: size of fw image
+ * @modules : # of modules
+ * @file_format : version of header format
+ * @reserved : reserved fields
+ */
+struct sst_fw_header {
+       unsigned char signature[FW_SIGNATURE_SIZE];
+       u32 file_size;
+       u32 modules;
+       u32 file_format;
+       u32 reserved[4];
+};
+
+/**
+ * struct fw_module_header - module header in FW
+ *
+ * @signature: module signature
+ * @mod_size: size of module
+ * @blocks: block count
+ * @type: block type
+ * @entry_point: module netry point
+ */
+struct fw_module_header {
+       unsigned char signature[FW_SIGNATURE_SIZE];
+       u32 mod_size;
+       u32 blocks;
+       u32 type;
+       u32 entry_point;
+};
+
+/**
+ * struct fw_block_info - block header for FW
+ *
+ * @type: block ram type I/D
+ * @size: size of block
+ * @ram_offset: offset in ram
+ */
+struct fw_block_info {
+       enum sst_ram_type       type;
+       u32                     size;
+       u32                     ram_offset;
+       u32                     rsvd;
+};
+
+struct sst_runtime_param {
+       struct snd_sst_runtime_params param;
+};
+
+struct sst_sg_list {
+       struct scatterlist *src;
+       struct scatterlist *dst;
+       int list_len;
+       unsigned int sg_idx;
+};
+
+struct sst_memcpy_list {
+       struct list_head memcpylist;
+       void *dstn;
+       const void *src;
+       u32 size;
+       bool is_io;
+};
+
+/*Firmware Module Information*/
+enum sst_lib_dwnld_status {
+       SST_LIB_NOT_FOUND = 0,
+       SST_LIB_FOUND,
+       SST_LIB_DOWNLOADED,
+};
+
+struct sst_module_info {
+       const char *name; /*Library name*/
+       u32     id; /*Module ID*/
+       u32     entry_pt; /*Module entry point*/
+       u8      status; /*module status*/
+       u8      rsvd1;
+       u16     rsvd2;
+};
+
+/*
+ * Structure for managing the Library Region(1.5MB)
+ * in DDR in Merrifield
+ */
+struct sst_mem_mgr {
+       phys_addr_t current_base;
+       int avail;
+       unsigned int count;
+};
+
+struct sst_ipc_reg {
+       int ipcx;
+       int ipcd;
+};
+
+struct sst_shim_regs64 {
+       u64 csr;
+       u64 pisr;
+       u64 pimr;
+       u64 isrx;
+       u64 isrd;
+       u64 imrx;
+       u64 imrd;
+       u64 ipcx;
+       u64 ipcd;
+       u64 isrsc;
+       u64 isrlpesc;
+       u64 imrsc;
+       u64 imrlpesc;
+       u64 ipcsc;
+       u64 ipclpesc;
+       u64 clkctl;
+       u64 csr2;
+};
+
+struct sst_fw_save {
+       void *iram;
+       void *dram;
+       void *sram;
+       void *ddr;
+};
+
+/**
+ * struct intel_sst_drv - driver ops
+ *
+ * @sst_state : current sst device state
+ * @dev_id : device identifier, pci_id for pci devices and acpi_id for acpi
+ *          devices
+ * @shim : SST shim pointer
+ * @mailbox : SST mailbox pointer
+ * @iram : SST IRAM pointer
+ * @dram : SST DRAM pointer
+ * @pdata : SST info passed as a part of pci platform data
+ * @shim_phy_add : SST shim phy addr
+ * @shim_regs64: Struct to save shim registers
+ * @ipc_dispatch_list : ipc messages dispatched
+ * @rx_list : to copy the process_reply/process_msg from DSP
+ * @ipc_post_msg_wq : wq to post IPC messages context
+ * @mad_ops : MAD driver operations registered
+ * @mad_wq : MAD driver wq
+ * @post_msg_wq : wq to post IPC messages
+ * @streams : sst stream contexts
+ * @list_lock : sst driver list lock (deprecated)
+ * @ipc_spin_lock : spin lock to handle audio shim access and ipc queue
+ * @block_lock : spin lock to add block to block_list and assign pvt_id
+ * @rx_msg_lock : spin lock to handle the rx messages from the DSP
+ * @scard_ops : sst card ops
+ * @pci : sst pci device struture
+ * @dev : pointer to current device struct
+ * @sst_lock : sst device lock
+ * @pvt_id : sst private id
+ * @stream_cnt : total sst active stream count
+ * @pb_streams : total active pb streams
+ * @cp_streams : total active cp streams
+ * @audio_start : audio status
+ * @qos                : PM Qos struct
+ * firmware_name : Firmware / Library name
+ */
+struct intel_sst_drv {
+       int                     sst_state;
+       int                     irq_num;
+       unsigned int            dev_id;
+       void __iomem            *ddr;
+       void __iomem            *shim;
+       void __iomem            *mailbox;
+       void __iomem            *iram;
+       void __iomem            *dram;
+       unsigned int            mailbox_add;
+       unsigned int            iram_base;
+       unsigned int            dram_base;
+       unsigned int            shim_phy_add;
+       unsigned int            iram_end;
+       unsigned int            dram_end;
+       unsigned int            ddr_end;
+       unsigned int            ddr_base;
+       unsigned int            mailbox_recv_offset;
+       struct sst_shim_regs64  *shim_regs64;
+       struct list_head        block_list;
+       struct list_head        ipc_dispatch_list;
+       struct sst_platform_info *pdata;
+       struct list_head        rx_list;
+       struct work_struct      ipc_post_msg_wq;
+       wait_queue_head_t       wait_queue;
+       struct workqueue_struct *post_msg_wq;
+       unsigned int            tstamp;
+       /* str_id 0 is not used */
+       struct stream_info      streams[MAX_NUM_STREAMS+1];
+       spinlock_t              ipc_spin_lock;
+       spinlock_t              block_lock;
+       spinlock_t              rx_msg_lock;
+       struct pci_dev          *pci;
+       struct device           *dev;
+       volatile long unsigned          pvt_id;
+       struct mutex            sst_lock;
+       unsigned int            stream_cnt;
+       unsigned int            csr_value;
+       void                    *fw_in_mem;
+       struct sst_sg_list      fw_sg_list, library_list;
+       struct intel_sst_ops    *ops;
+       struct sst_info         info;
+       struct pm_qos_request   *qos;
+       unsigned int            use_dma;
+       unsigned int            use_lli;
+       atomic_t                fw_clear_context;
+       bool                    lib_dwnld_reqd;
+       struct list_head        memcpy_list;
+       struct sst_ipc_reg      ipc_reg;
+       struct sst_mem_mgr      lib_mem_mgr;
+       /*
+        * Holder for firmware name. Due to async call it needs to be
+        * persistent till worker thread gets called
+        */
+       char firmware_name[FW_NAME_SIZE];
+
+       struct sst_fw_save      *fw_save;
+};
+
+/* misc definitions */
+#define FW_DWNL_ID 0x01
+
+struct intel_sst_ops {
+       irqreturn_t (*interrupt)(int, void *);
+       irqreturn_t (*irq_thread)(int, void *);
+       void (*clear_interrupt)(struct intel_sst_drv *ctx);
+       int (*start)(struct intel_sst_drv *ctx);
+       int (*reset)(struct intel_sst_drv *ctx);
+       void (*process_reply)(struct intel_sst_drv *ctx, struct ipc_post *msg);
+       int (*post_message)(struct intel_sst_drv *ctx,
+                       struct ipc_post *msg, bool sync);
+       void (*process_message)(struct ipc_post *msg);
+       void (*set_bypass)(bool set);
+       int (*save_dsp_context)(struct intel_sst_drv *sst);
+       void (*restore_dsp_context)(void);
+       int (*alloc_stream)(struct intel_sst_drv *ctx, void *params);
+       void (*post_download)(struct intel_sst_drv *sst);
+};
+
+int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int id);
+int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int id);
+int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int id);
+int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int id);
+int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id);
+int sst_send_byte_stream_mrfld(struct intel_sst_drv *ctx,
+                       struct snd_sst_bytes_v2 *sbytes);
+int sst_set_stream_param(int str_id, struct snd_sst_params *str_param);
+int sst_set_metadata(int str_id, char *params);
+int sst_get_stream(struct intel_sst_drv *sst_drv_ctx,
+               struct snd_sst_params *str_param);
+int sst_get_stream_allocated(struct intel_sst_drv *ctx,
+               struct snd_sst_params *str_param,
+               struct snd_sst_lib_download **lib_dnld);
+int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
+               int str_id, bool partial_drain);
+int sst_post_message_mrfld(struct intel_sst_drv *ctx,
+               struct ipc_post *msg, bool sync);
+void sst_process_reply_mrfld(struct intel_sst_drv *ctx, struct ipc_post *msg);
+int sst_start_mrfld(struct intel_sst_drv *ctx);
+int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *ctx);
+void intel_sst_clear_intr_mrfld(struct intel_sst_drv *ctx);
+
+int sst_load_fw(struct intel_sst_drv *ctx);
+int sst_load_library(struct snd_sst_lib_download *lib, u8 ops);
+void sst_post_download_mrfld(struct intel_sst_drv *ctx);
+int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx);
+void sst_memcpy_free_resources(struct intel_sst_drv *ctx);
+
+int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
+                               struct sst_block *block);
+int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
+                       struct sst_block *block);
+int sst_create_ipc_msg(struct ipc_post **arg, bool large);
+int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id);
+void sst_clean_stream(struct stream_info *stream);
+int intel_sst_register_compress(struct intel_sst_drv *sst);
+int intel_sst_remove_compress(struct intel_sst_drv *sst);
+void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id);
+int sst_send_sync_msg(int ipc, int str_id);
+int sst_get_num_channel(struct snd_sst_params *str_param);
+int sst_get_sfreq(struct snd_sst_params *str_param);
+int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params);
+void sst_restore_fw_context(void);
+struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
+                               u32 msg_id, u32 drv_id);
+int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large,
+               struct intel_sst_drv *sst_drv_ctx, struct sst_block **block,
+               u32 msg_id, u32 drv_id);
+int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed);
+int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
+               u32 drv_id, u32 ipc, void *data, u32 size);
+int sst_request_firmware_async(struct intel_sst_drv *ctx);
+int sst_driver_ops(struct intel_sst_drv *sst);
+struct sst_platform_info *sst_get_acpi_driver_data(const char *hid);
+void sst_firmware_load_cb(const struct firmware *fw, void *context);
+int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
+               int task_id, int ipc_msg, int cmd_id, int pipe_id,
+               size_t mbox_data_len, const void *mbox_data, void **data,
+               bool large, bool fill_dsp, bool sync, bool response);
+
+void sst_process_pending_msg(struct work_struct *work);
+int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx);
+void sst_init_stream(struct stream_info *stream,
+               int codec, int sst_id, int ops, u8 slot);
+int sst_validate_strid(struct intel_sst_drv *sst_drv_ctx, int str_id);
+struct stream_info *get_stream_info(struct intel_sst_drv *sst_drv_ctx,
+               int str_id);
+int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx,
+               u32 pipe_id);
+u32 relocate_imr_addr_mrfld(u32 base_addr);
+void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst,
+                                       struct ipc_post *msg);
+int sst_pm_runtime_put(struct intel_sst_drv *sst_drv);
+int sst_shim_write(void __iomem *addr, int offset, int value);
+u32 sst_shim_read(void __iomem *addr, int offset);
+u64 sst_reg_read64(void __iomem *addr, int offset);
+int sst_shim_write64(void __iomem *addr, int offset, u64 value);
+u64 sst_shim_read64(void __iomem *addr, int offset);
+void sst_set_fw_state_locked(
+               struct intel_sst_drv *sst_drv_ctx, int sst_state);
+void sst_fill_header_mrfld(union ipc_header_mrfld *header,
+                               int msg, int task_id, int large, int drv_id);
+void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg,
+                                       int pipe_id, int len);
+
+int sst_register(struct device *);
+int sst_unregister(struct device *);
+
+int sst_alloc_drv_context(struct intel_sst_drv **ctx,
+               struct device *dev, unsigned int dev_id);
+int sst_context_init(struct intel_sst_drv *ctx);
+void sst_context_cleanup(struct intel_sst_drv *ctx);
+void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
+void memcpy32_toio(void __iomem *dst, const void *src, int count);
+void memcpy32_fromio(void *dst, const void __iomem *src, int count);
+
+#endif
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
new file mode 100644 (file)
index 0000000..05f6930
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * sst_acpi.c - SST (LPE) driver init file for ACPI enumeration.
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ *  Authors:   Ramesh Babu K V <Ramesh.Babu@intel.com>
+ *  Authors:   Omair Mohammed Abdullah <omair.m.abdullah@intel.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,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/acpi.h>
+#include <asm/platform_sst_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <acpi/acbuffer.h>
+#include <acpi/platform/acenv.h>
+#include <acpi/platform/aclinux.h>
+#include <acpi/actypes.h>
+#include <acpi/acpi_bus.h>
+#include "../sst-mfld-platform.h"
+#include "../../common/sst-dsp.h"
+#include "sst.h"
+
+struct sst_machines {
+       char *codec_id;
+       char board[32];
+       char machine[32];
+       void (*machine_quirk)(void);
+       char firmware[FW_NAME_SIZE];
+       struct sst_platform_info *pdata;
+
+};
+
+/* LPE viewpoint addresses */
+#define SST_BYT_IRAM_PHY_START 0xff2c0000
+#define SST_BYT_IRAM_PHY_END   0xff2d4000
+#define SST_BYT_DRAM_PHY_START 0xff300000
+#define SST_BYT_DRAM_PHY_END   0xff320000
+#define SST_BYT_IMR_VIRT_START 0xc0000000 /* virtual addr in LPE */
+#define SST_BYT_IMR_VIRT_END   0xc01fffff
+#define SST_BYT_SHIM_PHY_ADDR  0xff340000
+#define SST_BYT_MBOX_PHY_ADDR  0xff344000
+#define SST_BYT_DMA0_PHY_ADDR  0xff298000
+#define SST_BYT_DMA1_PHY_ADDR  0xff29c000
+#define SST_BYT_SSP0_PHY_ADDR  0xff2a0000
+#define SST_BYT_SSP2_PHY_ADDR  0xff2a2000
+
+#define BYT_FW_MOD_TABLE_OFFSET        0x80000
+#define BYT_FW_MOD_TABLE_SIZE  0x100
+#define BYT_FW_MOD_OFFSET      (BYT_FW_MOD_TABLE_OFFSET + BYT_FW_MOD_TABLE_SIZE)
+
+static const struct sst_info byt_fwparse_info = {
+       .use_elf        = false,
+       .max_streams    = 25,
+       .iram_start     = SST_BYT_IRAM_PHY_START,
+       .iram_end       = SST_BYT_IRAM_PHY_END,
+       .iram_use       = true,
+       .dram_start     = SST_BYT_DRAM_PHY_START,
+       .dram_end       = SST_BYT_DRAM_PHY_END,
+       .dram_use       = true,
+       .imr_start      = SST_BYT_IMR_VIRT_START,
+       .imr_end        = SST_BYT_IMR_VIRT_END,
+       .imr_use        = true,
+       .mailbox_start  = SST_BYT_MBOX_PHY_ADDR,
+       .num_probes     = 0,
+       .lpe_viewpt_rqd  = true,
+};
+
+static const struct sst_ipc_info byt_ipc_info = {
+       .ipc_offset = 0,
+       .mbox_recv_off = 0x400,
+};
+
+static const struct sst_lib_dnld_info  byt_lib_dnld_info = {
+       .mod_base           = SST_BYT_IMR_VIRT_START,
+       .mod_end            = SST_BYT_IMR_VIRT_END,
+       .mod_table_offset   = BYT_FW_MOD_TABLE_OFFSET,
+       .mod_table_size     = BYT_FW_MOD_TABLE_SIZE,
+       .mod_ddr_dnld       = false,
+};
+
+static const struct sst_res_info byt_rvp_res_info = {
+       .shim_offset = 0x140000,
+       .shim_size = 0x000100,
+       .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
+       .ssp0_offset = 0xa0000,
+       .ssp0_size = 0x1000,
+       .dma0_offset = 0x98000,
+       .dma0_size = 0x4000,
+       .dma1_offset = 0x9c000,
+       .dma1_size = 0x4000,
+       .iram_offset = 0x0c0000,
+       .iram_size = 0x14000,
+       .dram_offset = 0x100000,
+       .dram_size = 0x28000,
+       .mbox_offset = 0x144000,
+       .mbox_size = 0x1000,
+       .acpi_lpe_res_index = 0,
+       .acpi_ddr_index = 2,
+       .acpi_ipc_irq_index = 5,
+};
+
+static struct sst_platform_info byt_rvp_platform_data = {
+       .probe_data = &byt_fwparse_info,
+       .ipc_info = &byt_ipc_info,
+       .lib_info = &byt_lib_dnld_info,
+       .res_info = &byt_rvp_res_info,
+       .platform = "sst-mfld-platform",
+};
+
+/* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail,
+ * so pdata is same as Baytrail.
+ */
+static struct sst_platform_info chv_platform_data = {
+       .probe_data = &byt_fwparse_info,
+       .ipc_info = &byt_ipc_info,
+       .lib_info = &byt_lib_dnld_info,
+       .res_info = &byt_rvp_res_info,
+       .platform = "sst-mfld-platform",
+};
+
+static int sst_platform_get_resources(struct intel_sst_drv *ctx)
+{
+       struct resource *rsrc;
+       struct platform_device *pdev = to_platform_device(ctx->dev);
+
+       /* All ACPI resource request here */
+       /* Get Shim addr */
+       rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
+                                       ctx->pdata->res_info->acpi_lpe_res_index);
+       if (!rsrc) {
+               dev_err(ctx->dev, "Invalid SHIM base from IFWI");
+               return -EIO;
+       }
+       dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start,
+                                       (unsigned int)resource_size(rsrc));
+
+       ctx->iram_base = rsrc->start + ctx->pdata->res_info->iram_offset;
+       ctx->iram_end =  ctx->iram_base + ctx->pdata->res_info->iram_size - 1;
+       dev_info(ctx->dev, "IRAM base: %#x", ctx->iram_base);
+       ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base,
+                                        ctx->pdata->res_info->iram_size);
+       if (!ctx->iram) {
+               dev_err(ctx->dev, "unable to map IRAM");
+               return -EIO;
+       }
+
+       ctx->dram_base = rsrc->start + ctx->pdata->res_info->dram_offset;
+       ctx->dram_end = ctx->dram_base + ctx->pdata->res_info->dram_size - 1;
+       dev_info(ctx->dev, "DRAM base: %#x", ctx->dram_base);
+       ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base,
+                                        ctx->pdata->res_info->dram_size);
+       if (!ctx->dram) {
+               dev_err(ctx->dev, "unable to map DRAM");
+               return -EIO;
+       }
+
+       ctx->shim_phy_add = rsrc->start + ctx->pdata->res_info->shim_offset;
+       dev_info(ctx->dev, "SHIM base: %#x", ctx->shim_phy_add);
+       ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add,
+                                       ctx->pdata->res_info->shim_size);
+       if (!ctx->shim) {
+               dev_err(ctx->dev, "unable to map SHIM");
+               return -EIO;
+       }
+
+       /* reassign physical address to LPE viewpoint address */
+       ctx->shim_phy_add = ctx->pdata->res_info->shim_phy_addr;
+
+       /* Get mailbox addr */
+       ctx->mailbox_add = rsrc->start + ctx->pdata->res_info->mbox_offset;
+       dev_info(ctx->dev, "Mailbox base: %#x", ctx->mailbox_add);
+       ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add,
+                                           ctx->pdata->res_info->mbox_size);
+       if (!ctx->mailbox) {
+               dev_err(ctx->dev, "unable to map mailbox");
+               return -EIO;
+       }
+
+       /* reassign physical address to LPE viewpoint address */
+       ctx->mailbox_add = ctx->info.mailbox_start;
+
+       rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
+                                       ctx->pdata->res_info->acpi_ddr_index);
+       if (!rsrc) {
+               dev_err(ctx->dev, "Invalid DDR base from IFWI");
+               return -EIO;
+       }
+       ctx->ddr_base = rsrc->start;
+       ctx->ddr_end = rsrc->end;
+       dev_info(ctx->dev, "DDR base: %#x", ctx->ddr_base);
+       ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base,
+                                       resource_size(rsrc));
+       if (!ctx->ddr) {
+               dev_err(ctx->dev, "unable to map DDR");
+               return -EIO;
+       }
+
+       /* Find the IRQ */
+       ctx->irq_num = platform_get_irq(pdev,
+                               ctx->pdata->res_info->acpi_ipc_irq_index);
+       return 0;
+}
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+                                      void *context, void **ret)
+{
+       *(bool *)context = true;
+       return AE_OK;
+}
+
+static struct sst_machines *sst_acpi_find_machine(
+       struct sst_machines *machines)
+{
+       struct sst_machines *mach;
+       bool found = false;
+
+       for (mach = machines; mach->codec_id; mach++)
+               if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id,
+                                                 sst_acpi_mach_match,
+                                                 &found, NULL)) && found)
+                       return mach;
+
+       return NULL;
+}
+
+static int sst_acpi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       int ret = 0;
+       struct intel_sst_drv *ctx;
+       const struct acpi_device_id *id;
+       struct sst_machines *mach;
+       struct platform_device *mdev;
+       struct platform_device *plat_dev;
+       unsigned int dev_id;
+
+       id = acpi_match_device(dev->driver->acpi_match_table, dev);
+       if (!id)
+               return -ENODEV;
+       dev_dbg(dev, "for %s", id->id);
+
+       mach = (struct sst_machines *)id->driver_data;
+       mach = sst_acpi_find_machine(mach);
+       if (mach == NULL) {
+               dev_err(dev, "No matching machine driver found\n");
+               return -ENODEV;
+       }
+
+       ret = kstrtouint(id->id, 16, &dev_id);
+       if (ret < 0) {
+               dev_err(dev, "Unique device id conversion error: %d\n", ret);
+               return ret;
+       }
+
+       dev_dbg(dev, "ACPI device id: %x\n", dev_id);
+
+       plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0);
+       if (IS_ERR(plat_dev)) {
+               dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform);
+               return PTR_ERR(plat_dev);
+       }
+
+       /* Create platform device for sst machine driver */
+       mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0);
+       if (IS_ERR(mdev)) {
+               dev_err(dev, "Failed to create machine device: %s\n", mach->machine);
+               return PTR_ERR(mdev);
+       }
+
+       ret = sst_alloc_drv_context(&ctx, dev, dev_id);
+       if (ret < 0)
+               return ret;
+
+       /* Fill sst platform data */
+       ctx->pdata = mach->pdata;
+       strcpy(ctx->firmware_name, mach->firmware);
+
+       ret = sst_platform_get_resources(ctx);
+       if (ret)
+               return ret;
+
+       ret = sst_context_init(ctx);
+       if (ret < 0)
+               return ret;
+
+       /* need to save shim registers in BYT */
+       ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64),
+                                       GFP_KERNEL);
+       if (!ctx->shim_regs64) {
+               ret = -ENOMEM;
+               goto do_sst_cleanup;
+       }
+
+       sst_configure_runtime_pm(ctx);
+       platform_set_drvdata(pdev, ctx);
+       return ret;
+
+do_sst_cleanup:
+       sst_context_cleanup(ctx);
+       platform_set_drvdata(pdev, NULL);
+       dev_err(ctx->dev, "failed with %d\n", ret);
+       return ret;
+}
+
+/**
+* intel_sst_remove - remove function
+*
+* @pdev:       platform device structure
+*
+* This function is called by OS when a device is unloaded
+* This frees the interrupt etc
+*/
+static int sst_acpi_remove(struct platform_device *pdev)
+{
+       struct intel_sst_drv *ctx;
+
+       ctx = platform_get_drvdata(pdev);
+       sst_context_cleanup(ctx);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct sst_machines sst_acpi_bytcr[] = {
+       {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin",
+                                               &byt_rvp_platform_data },
+       {},
+};
+
+/* Cherryview-based platforms: CherryTrail and Braswell */
+static struct sst_machines sst_acpi_chv[] = {
+       {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin",
+                                               &chv_platform_data },
+       {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+                                               &chv_platform_data },
+       {},
+};
+
+static const struct acpi_device_id sst_acpi_ids[] = {
+       { "80860F28", (unsigned long)&sst_acpi_bytcr},
+       { "808622A8", (unsigned long) &sst_acpi_chv},
+       { },
+};
+
+MODULE_DEVICE_TABLE(acpi, sst_acpi_ids);
+
+static struct platform_driver sst_acpi_driver = {
+       .driver = {
+               .name                   = "intel_sst_acpi",
+               .acpi_match_table       = ACPI_PTR(sst_acpi_ids),
+               .pm                     = &intel_sst_pm,
+       },
+       .probe  = sst_acpi_probe,
+       .remove = sst_acpi_remove,
+};
+
+module_platform_driver(sst_acpi_driver);
+
+MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine ACPI Driver");
+MODULE_AUTHOR("Ramesh Babu K V");
+MODULE_AUTHOR("Omair Mohammed Abdullah");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("sst");
diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c
new file mode 100644 (file)
index 0000000..7b50a9d
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ *  sst_drv_interface.c - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-14 Intel Corp
+ *  Authors:   Vinod Koul <vinod.koul@intel.com>
+ *             Harsha Priya <priya.harsha@intel.com>
+ *             Dharageswari R <dharageswari.r@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/math64.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../../common/sst-dsp.h"
+
+
+
+#define NUM_CODEC 2
+#define MIN_FRAGMENT 2
+#define MAX_FRAGMENT 4
+#define MIN_FRAGMENT_SIZE (50 * 1024)
+#define MAX_FRAGMENT_SIZE (1024 * 1024)
+#define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz)  (((pcm_wd_sz + 15) >> 4) << 1)
+
+int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id)
+{
+       struct stream_info *stream;
+       int ret = 0;
+
+       stream = get_stream_info(ctx, str_id);
+       if (stream) {
+               /* str_id is valid, so stream is alloacted */
+               ret = sst_free_stream(ctx, str_id);
+               if (ret)
+                       sst_clean_stream(&ctx->streams[str_id]);
+               return ret;
+       } else {
+               dev_err(ctx->dev, "we tried to free stream context %d which was freed!!!\n", str_id);
+       }
+       return ret;
+}
+
+int sst_get_stream_allocated(struct intel_sst_drv *ctx,
+       struct snd_sst_params *str_param,
+       struct snd_sst_lib_download **lib_dnld)
+{
+       int retval;
+
+       retval = ctx->ops->alloc_stream(ctx, str_param);
+       if (retval > 0)
+               dev_dbg(ctx->dev, "Stream allocated %d\n", retval);
+       return retval;
+
+}
+
+/*
+ * sst_get_sfreq - this function returns the frequency of the stream
+ *
+ * @str_param : stream params
+ */
+int sst_get_sfreq(struct snd_sst_params *str_param)
+{
+       switch (str_param->codec) {
+       case SST_CODEC_TYPE_PCM:
+               return str_param->sparams.uc.pcm_params.sfreq;
+       case SST_CODEC_TYPE_AAC:
+               return str_param->sparams.uc.aac_params.externalsr;
+       case SST_CODEC_TYPE_MP3:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * sst_get_num_channel - get number of channels for the stream
+ *
+ * @str_param : stream params
+ */
+int sst_get_num_channel(struct snd_sst_params *str_param)
+{
+       switch (str_param->codec) {
+       case SST_CODEC_TYPE_PCM:
+               return str_param->sparams.uc.pcm_params.num_chan;
+       case SST_CODEC_TYPE_MP3:
+               return str_param->sparams.uc.mp3_params.num_chan;
+       case SST_CODEC_TYPE_AAC:
+               return str_param->sparams.uc.aac_params.num_chan;
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * sst_get_stream - this function prepares for stream allocation
+ *
+ * @str_param : stream param
+ */
+int sst_get_stream(struct intel_sst_drv *ctx,
+                       struct snd_sst_params *str_param)
+{
+       int retval;
+       struct stream_info *str_info;
+
+       /* stream is not allocated, we are allocating */
+       retval = ctx->ops->alloc_stream(ctx, str_param);
+       if (retval <= 0) {
+               return -EIO;
+       }
+       /* store sampling freq */
+       str_info = &ctx->streams[retval];
+       str_info->sfreq = sst_get_sfreq(str_param);
+
+       return retval;
+}
+
+static int sst_power_control(struct device *dev, bool state)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+       int ret = 0;
+       int usage_count = 0;
+
+#ifdef CONFIG_PM
+       usage_count = atomic_read(&dev->power.usage_count);
+#else
+       usage_count = 1;
+#endif
+
+       if (state == true) {
+               ret = pm_runtime_get_sync(dev);
+
+               dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
+               if (ret < 0) {
+                       dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
+                       return ret;
+               }
+               if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) {
+                       ret = sst_load_fw(ctx);
+                       if (ret) {
+                               dev_err(dev, "FW download fail %d\n", ret);
+                               sst_set_fw_state_locked(ctx, SST_RESET);
+                               ret = sst_pm_runtime_put(ctx);
+                       }
+               }
+       } else {
+               dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count);
+               return sst_pm_runtime_put(ctx);
+       }
+       return ret;
+}
+
+/*
+ * sst_open_pcm_stream - Open PCM interface
+ *
+ * @str_param: parameters of pcm stream
+ *
+ * This function is called by MID sound card driver to open
+ * a new pcm interface
+ */
+static int sst_open_pcm_stream(struct device *dev,
+               struct snd_sst_params *str_param)
+{
+       int retval;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (!str_param)
+               return -EINVAL;
+
+       retval = sst_get_stream(ctx, str_param);
+       if (retval > 0)
+               ctx->stream_cnt++;
+       else
+               dev_err(ctx->dev, "sst_get_stream returned err %d\n", retval);
+
+       return retval;
+}
+
+static int sst_cdev_open(struct device *dev,
+               struct snd_sst_params *str_params, struct sst_compress_cb *cb)
+{
+       int str_id, retval;
+       struct stream_info *stream;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       retval = pm_runtime_get_sync(ctx->dev);
+       if (retval < 0)
+               return retval;
+
+       str_id = sst_get_stream(ctx, str_params);
+       if (str_id > 0) {
+               dev_dbg(dev, "stream allocated in sst_cdev_open %d\n", str_id);
+               stream = &ctx->streams[str_id];
+               stream->compr_cb = cb->compr_cb;
+               stream->compr_cb_param = cb->param;
+               stream->drain_notify = cb->drain_notify;
+               stream->drain_cb_param = cb->drain_cb_param;
+       } else {
+               dev_err(dev, "stream encountered error during alloc %d\n", str_id);
+               str_id = -EINVAL;
+               sst_pm_runtime_put(ctx);
+       }
+       return str_id;
+}
+
+static int sst_cdev_close(struct device *dev, unsigned int str_id)
+{
+       int retval;
+       struct stream_info *stream;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       stream = get_stream_info(ctx, str_id);
+       if (!stream) {
+               dev_err(dev, "stream info is NULL for str %d!!!\n", str_id);
+               return -EINVAL;
+       }
+
+       if (stream->status == STREAM_RESET) {
+               dev_dbg(dev, "stream in reset state...\n");
+               stream->status = STREAM_UN_INIT;
+
+               retval = 0;
+               goto put;
+       }
+
+       retval = sst_free_stream(ctx, str_id);
+put:
+       stream->compr_cb_param = NULL;
+       stream->compr_cb = NULL;
+
+       if (retval)
+               dev_err(dev, "free stream returned err %d\n", retval);
+
+       dev_dbg(dev, "End\n");
+       return retval;
+
+}
+
+static int sst_cdev_ack(struct device *dev, unsigned int str_id,
+               unsigned long bytes)
+{
+       struct stream_info *stream;
+       struct snd_sst_tstamp fw_tstamp = {0,};
+       int offset;
+       void __iomem *addr;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       stream = get_stream_info(ctx, str_id);
+       if (!stream)
+               return -EINVAL;
+
+       /* update bytes sent */
+       stream->cumm_bytes += bytes;
+       dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes);
+
+       memcpy_fromio(&fw_tstamp,
+               ((void *)(ctx->mailbox + ctx->tstamp)
+               +(str_id * sizeof(fw_tstamp))),
+               sizeof(fw_tstamp));
+
+       fw_tstamp.bytes_copied = stream->cumm_bytes;
+       dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n",
+                       fw_tstamp.bytes_copied, bytes);
+
+       addr =  ((void *)(ctx->mailbox + ctx->tstamp)) +
+                       (str_id * sizeof(fw_tstamp));
+       offset =  offsetof(struct snd_sst_tstamp, bytes_copied);
+       sst_shim_write(addr, offset, fw_tstamp.bytes_copied);
+       return 0;
+}
+
+static int sst_cdev_set_metadata(struct device *dev,
+               unsigned int str_id, struct snd_compr_metadata *metadata)
+{
+       int retval = 0;
+       struct stream_info *str_info;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "set metadata for stream %d\n", str_id);
+
+       str_info = get_stream_info(ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+
+       dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id);
+       retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD,
+                       IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id,
+                       sizeof(*metadata), metadata, NULL,
+                       true, true, true, false);
+
+       return retval;
+}
+
+static int sst_cdev_stream_pause(struct device *dev, unsigned int str_id)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       return sst_pause_stream(ctx, str_id);
+}
+
+static int sst_cdev_stream_pause_release(struct device *dev,
+               unsigned int str_id)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       return sst_resume_stream(ctx, str_id);
+}
+
+static int sst_cdev_stream_start(struct device *dev, unsigned int str_id)
+{
+       struct stream_info *str_info;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       str_info = get_stream_info(ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       str_info->prev = str_info->status;
+       str_info->status = STREAM_RUNNING;
+       return sst_start_stream(ctx, str_id);
+}
+
+static int sst_cdev_stream_drop(struct device *dev, unsigned int str_id)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       return sst_drop_stream(ctx, str_id);
+}
+
+static int sst_cdev_stream_drain(struct device *dev, unsigned int str_id)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       return sst_drain_stream(ctx, str_id, false);
+}
+
+static int sst_cdev_stream_partial_drain(struct device *dev,
+               unsigned int str_id)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       return sst_drain_stream(ctx, str_id, true);
+}
+
+static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
+               struct snd_compr_tstamp *tstamp)
+{
+       struct snd_sst_tstamp fw_tstamp = {0,};
+       struct stream_info *stream;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       memcpy_fromio(&fw_tstamp,
+               ((void *)(ctx->mailbox + ctx->tstamp)
+               +(str_id * sizeof(fw_tstamp))),
+               sizeof(fw_tstamp));
+
+       stream = get_stream_info(ctx, str_id);
+       if (!stream)
+               return -EINVAL;
+       dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter);
+
+       tstamp->copied_total = fw_tstamp.ring_buffer_counter;
+       tstamp->pcm_frames = fw_tstamp.frames_decoded;
+       tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter,
+                       (u64)stream->num_ch * SST_GET_BYTES_PER_SAMPLE(24));
+       tstamp->sampling_rate = fw_tstamp.sampling_frequency;
+
+       dev_dbg(dev, "PCM  = %u\n", tstamp->pcm_io_frames);
+       dev_dbg(dev, "Ptr Query on strid = %d  copied_total %d, decodec %d\n",
+               str_id, tstamp->copied_total, tstamp->pcm_frames);
+       dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames);
+
+       return 0;
+}
+
+static int sst_cdev_caps(struct snd_compr_caps *caps)
+{
+       caps->num_codecs = NUM_CODEC;
+       caps->min_fragment_size = MIN_FRAGMENT_SIZE;  /* 50KB */
+       caps->max_fragment_size = MAX_FRAGMENT_SIZE;  /* 1024KB */
+       caps->min_fragments = MIN_FRAGMENT;
+       caps->max_fragments = MAX_FRAGMENT;
+       caps->codecs[0] = SND_AUDIOCODEC_MP3;
+       caps->codecs[1] = SND_AUDIOCODEC_AAC;
+       return 0;
+}
+
+static struct snd_compr_codec_caps caps_mp3 = {
+       .num_descriptors = 1,
+       .descriptor[0].max_ch = 2,
+       .descriptor[0].sample_rates[0] = 48000,
+       .descriptor[0].sample_rates[1] = 44100,
+       .descriptor[0].sample_rates[2] = 32000,
+       .descriptor[0].sample_rates[3] = 16000,
+       .descriptor[0].sample_rates[4] = 8000,
+       .descriptor[0].num_sample_rates = 5,
+       .descriptor[0].bit_rate[0] = 320,
+       .descriptor[0].bit_rate[1] = 192,
+       .descriptor[0].num_bitrates = 2,
+       .descriptor[0].profiles = 0,
+       .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
+       .descriptor[0].formats = 0,
+};
+
+static struct snd_compr_codec_caps caps_aac = {
+       .num_descriptors = 2,
+       .descriptor[1].max_ch = 2,
+       .descriptor[0].sample_rates[0] = 48000,
+       .descriptor[0].sample_rates[1] = 44100,
+       .descriptor[0].sample_rates[2] = 32000,
+       .descriptor[0].sample_rates[3] = 16000,
+       .descriptor[0].sample_rates[4] = 8000,
+       .descriptor[0].num_sample_rates = 5,
+       .descriptor[1].bit_rate[0] = 320,
+       .descriptor[1].bit_rate[1] = 192,
+       .descriptor[1].num_bitrates = 2,
+       .descriptor[1].profiles = 0,
+       .descriptor[1].modes = 0,
+       .descriptor[1].formats =
+                       (SND_AUDIOSTREAMFORMAT_MP4ADTS |
+                               SND_AUDIOSTREAMFORMAT_RAW),
+};
+
+static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec)
+{
+       if (codec->codec == SND_AUDIOCODEC_MP3)
+               *codec = caps_mp3;
+       else if (codec->codec == SND_AUDIOCODEC_AAC)
+               *codec = caps_aac;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id)
+{
+       struct stream_info *stream;
+
+       dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n",
+                       str_id);
+       stream = &ctx->streams[str_id];
+       if (stream->compr_cb)
+               stream->compr_cb(stream->compr_cb_param);
+}
+
+/*
+ * sst_close_pcm_stream - Close PCM interface
+ *
+ * @str_id: stream id to be closed
+ *
+ * This function is called by MID sound card driver to close
+ * an existing pcm interface
+ */
+static int sst_close_pcm_stream(struct device *dev, unsigned int str_id)
+{
+       struct stream_info *stream;
+       int retval = 0;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       stream = get_stream_info(ctx, str_id);
+       if (!stream) {
+               dev_err(ctx->dev, "stream info is NULL for str %d!!!\n", str_id);
+               return -EINVAL;
+       }
+
+       if (stream->status == STREAM_RESET) {
+               /* silently fail here as we have cleaned the stream earlier */
+               dev_dbg(ctx->dev, "stream in reset state...\n");
+
+               retval = 0;
+               goto put;
+       }
+
+       retval = free_stream_context(ctx, str_id);
+put:
+       stream->pcm_substream = NULL;
+       stream->status = STREAM_UN_INIT;
+       stream->period_elapsed = NULL;
+       ctx->stream_cnt--;
+
+       if (retval)
+               dev_err(ctx->dev, "free stream returned err %d\n", retval);
+
+       dev_dbg(ctx->dev, "Exit\n");
+       return 0;
+}
+
+static inline int sst_calc_tstamp(struct intel_sst_drv *ctx,
+               struct pcm_stream_info *info,
+               struct snd_pcm_substream *substream,
+               struct snd_sst_tstamp *fw_tstamp)
+{
+       size_t delay_bytes, delay_frames;
+       size_t buffer_sz;
+       u32 pointer_bytes, pointer_samples;
+
+       dev_dbg(ctx->dev, "mrfld ring_buffer_counter %llu in bytes\n",
+                       fw_tstamp->ring_buffer_counter);
+       dev_dbg(ctx->dev, "mrfld hardware_counter %llu in bytes\n",
+                        fw_tstamp->hardware_counter);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               delay_bytes = (size_t) (fw_tstamp->ring_buffer_counter -
+                                       fw_tstamp->hardware_counter);
+       else
+               delay_bytes = (size_t) (fw_tstamp->hardware_counter -
+                                       fw_tstamp->ring_buffer_counter);
+       delay_frames = bytes_to_frames(substream->runtime, delay_bytes);
+       buffer_sz = snd_pcm_lib_buffer_bytes(substream);
+       div_u64_rem(fw_tstamp->ring_buffer_counter, buffer_sz, &pointer_bytes);
+       pointer_samples = bytes_to_samples(substream->runtime, pointer_bytes);
+
+       dev_dbg(ctx->dev, "pcm delay %zu in bytes\n", delay_bytes);
+
+       info->buffer_ptr = pointer_samples / substream->runtime->channels;
+
+       info->pcm_delay = delay_frames / substream->runtime->channels;
+       dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n",
+                       info->buffer_ptr, info->pcm_delay);
+       return 0;
+}
+
+static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info)
+{
+       struct stream_info *stream;
+       struct snd_pcm_substream *substream;
+       struct snd_sst_tstamp fw_tstamp;
+       unsigned int str_id;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       str_id = info->str_id;
+       stream = get_stream_info(ctx, str_id);
+       if (!stream)
+               return -EINVAL;
+
+       if (!stream->pcm_substream)
+               return -EINVAL;
+       substream = stream->pcm_substream;
+
+       memcpy_fromio(&fw_tstamp,
+               ((void *)(ctx->mailbox + ctx->tstamp)
+                       + (str_id * sizeof(fw_tstamp))),
+               sizeof(fw_tstamp));
+       return sst_calc_tstamp(ctx, info, substream, &fw_tstamp);
+}
+
+static int sst_stream_start(struct device *dev, int str_id)
+{
+       struct stream_info *str_info;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (ctx->sst_state != SST_FW_RUNNING)
+               return 0;
+       str_info = get_stream_info(ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       str_info->prev = str_info->status;
+       str_info->status = STREAM_RUNNING;
+       sst_start_stream(ctx, str_id);
+
+       return 0;
+}
+
+static int sst_stream_drop(struct device *dev, int str_id)
+{
+       struct stream_info *str_info;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (ctx->sst_state != SST_FW_RUNNING)
+               return 0;
+
+       str_info = get_stream_info(ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       str_info->prev = STREAM_UN_INIT;
+       str_info->status = STREAM_INIT;
+       return sst_drop_stream(ctx, str_id);
+}
+
+static int sst_stream_pause(struct device *dev, int str_id)
+{
+       struct stream_info *str_info;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (ctx->sst_state != SST_FW_RUNNING)
+               return 0;
+
+       str_info = get_stream_info(ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+
+       return sst_pause_stream(ctx, str_id);
+}
+
+static int sst_stream_resume(struct device *dev, int str_id)
+{
+       struct stream_info *str_info;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (ctx->sst_state != SST_FW_RUNNING)
+               return 0;
+
+       str_info = get_stream_info(ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       return sst_resume_stream(ctx, str_id);
+}
+
+static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info)
+{
+       int str_id = 0;
+       struct stream_info *stream;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       str_id = str_info->str_id;
+
+       if (ctx->sst_state != SST_FW_RUNNING)
+               return 0;
+
+       stream = get_stream_info(ctx, str_id);
+       if (!stream)
+               return -EINVAL;
+
+       dev_dbg(ctx->dev, "setting the period ptrs\n");
+       stream->pcm_substream = str_info->arg;
+       stream->period_elapsed = str_info->period_elapsed;
+       stream->sfreq = str_info->sfreq;
+       stream->prev = stream->status;
+       stream->status = STREAM_INIT;
+       dev_dbg(ctx->dev,
+               "pcm_substream %p, period_elapsed %p, sfreq %d, status %d\n",
+               stream->pcm_substream, stream->period_elapsed,
+               stream->sfreq, stream->status);
+
+       return 0;
+}
+
+/*
+ * sst_set_byte_stream - Set generic params
+ *
+ * @cmd: control cmd to be set
+ * @arg: command argument
+ *
+ * This function is called by MID sound card driver to configure
+ * SST runtime params.
+ */
+static int sst_send_byte_stream(struct device *dev,
+               struct snd_sst_bytes_v2 *bytes)
+{
+       int ret_val = 0;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (NULL == bytes)
+               return -EINVAL;
+       ret_val = pm_runtime_get_sync(ctx->dev);
+       if (ret_val < 0)
+               return ret_val;
+
+       ret_val = sst_send_byte_stream_mrfld(ctx, bytes);
+       sst_pm_runtime_put(ctx);
+
+       return ret_val;
+}
+
+static struct sst_ops pcm_ops = {
+       .open = sst_open_pcm_stream,
+       .stream_init = sst_stream_init,
+       .stream_start = sst_stream_start,
+       .stream_drop = sst_stream_drop,
+       .stream_pause = sst_stream_pause,
+       .stream_pause_release = sst_stream_resume,
+       .stream_read_tstamp = sst_read_timestamp,
+       .send_byte_stream = sst_send_byte_stream,
+       .close = sst_close_pcm_stream,
+       .power = sst_power_control,
+};
+
+static struct compress_sst_ops compr_ops = {
+       .open = sst_cdev_open,
+       .close = sst_cdev_close,
+       .stream_pause = sst_cdev_stream_pause,
+       .stream_pause_release = sst_cdev_stream_pause_release,
+       .stream_start = sst_cdev_stream_start,
+       .stream_drop = sst_cdev_stream_drop,
+       .stream_drain = sst_cdev_stream_drain,
+       .stream_partial_drain = sst_cdev_stream_partial_drain,
+       .tstamp = sst_cdev_tstamp,
+       .ack = sst_cdev_ack,
+       .get_caps = sst_cdev_caps,
+       .get_codec_caps = sst_cdev_codec_caps,
+       .set_metadata = sst_cdev_set_metadata,
+       .power = sst_power_control,
+};
+
+static struct sst_device sst_dsp_device = {
+       .name = "Intel(R) SST LPE",
+       .dev = NULL,
+       .ops = &pcm_ops,
+       .compr_ops = &compr_ops,
+};
+
+/*
+ * sst_register - function to register DSP
+ *
+ * This functions registers DSP with the platform driver
+ */
+int sst_register(struct device *dev)
+{
+       int ret_val;
+
+       sst_dsp_device.dev = dev;
+       ret_val = sst_register_dsp(&sst_dsp_device);
+       if (ret_val)
+               dev_err(dev, "Unable to register DSP with platform driver\n");
+
+       return ret_val;
+}
+
+int sst_unregister(struct device *dev)
+{
+       return sst_unregister_dsp(&sst_dsp_device);
+}
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
new file mode 100644 (file)
index 0000000..5a27861
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ *  sst_ipc.c - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-14 Intel Corporation
+ *  Authors:   Vinod Koul <vinod.koul@intel.com>
+ *             Harsha Priya <priya.harsha@intel.com>
+ *             Dharageswari R <dharageswari.r@intel.com>
+ *             KP Jeeja <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/intel-mid.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../../common/sst-dsp.h"
+
+struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
+                                       u32 msg_id, u32 drv_id)
+{
+       struct sst_block *msg = NULL;
+
+       dev_dbg(ctx->dev, "Enter\n");
+       msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+       if (!msg)
+               return NULL;
+       msg->condition = false;
+       msg->on = true;
+       msg->msg_id = msg_id;
+       msg->drv_id = drv_id;
+       spin_lock_bh(&ctx->block_lock);
+       list_add_tail(&msg->node, &ctx->block_list);
+       spin_unlock_bh(&ctx->block_lock);
+
+       return msg;
+}
+
+/*
+ * while handling the interrupts, we need to check for message status and
+ * then if we are blocking for a message
+ *
+ * here we are unblocking the blocked ones, this is based on id we have
+ * passed and search that for block threads.
+ * We will not find block in two cases
+ *  a) when its small message and block in not there, so silently ignore
+ *  them
+ *  b) when we are actually not able to find the block (bug perhaps)
+ *
+ *  Since we have bit of small messages we can spam kernel log with err
+ *  print on above so need to keep as debug prints which should be enabled
+ *  via dynamic debug while debugging IPC issues
+ */
+int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
+               u32 drv_id, u32 ipc, void *data, u32 size)
+{
+       struct sst_block *block = NULL;
+
+       dev_dbg(ctx->dev, "Enter\n");
+
+       spin_lock_bh(&ctx->block_lock);
+       list_for_each_entry(block, &ctx->block_list, node) {
+               dev_dbg(ctx->dev, "Block ipc %d, drv_id %d\n", block->msg_id,
+                                                       block->drv_id);
+               if (block->msg_id == ipc && block->drv_id == drv_id) {
+                       dev_dbg(ctx->dev, "free up the block\n");
+                       block->ret_code = result;
+                       block->data = data;
+                       block->size = size;
+                       block->condition = true;
+                       spin_unlock_bh(&ctx->block_lock);
+                       wake_up(&ctx->wait_queue);
+                       return 0;
+               }
+       }
+       spin_unlock_bh(&ctx->block_lock);
+       dev_dbg(ctx->dev,
+               "Block not found or a response received for a short msg for ipc %d, drv_id %d\n",
+               ipc, drv_id);
+       return -EINVAL;
+}
+
+int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed)
+{
+       struct sst_block *block = NULL, *__block;
+
+       dev_dbg(ctx->dev, "Enter\n");
+       spin_lock_bh(&ctx->block_lock);
+       list_for_each_entry_safe(block, __block, &ctx->block_list, node) {
+               if (block == freed) {
+                       pr_debug("pvt_id freed --> %d\n", freed->drv_id);
+                       /* toggle the index position of pvt_id */
+                       list_del(&freed->node);
+                       spin_unlock_bh(&ctx->block_lock);
+                       kfree(freed->data);
+                       freed->data = NULL;
+                       kfree(freed);
+                       return 0;
+               }
+       }
+       spin_unlock_bh(&ctx->block_lock);
+       dev_err(ctx->dev, "block is already freed!!!\n");
+       return -EINVAL;
+}
+
+int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx,
+               struct ipc_post *ipc_msg, bool sync)
+{
+       struct ipc_post *msg = ipc_msg;
+       union ipc_header_mrfld header;
+       unsigned int loop_count = 0;
+       int retval = 0;
+       unsigned long irq_flags;
+
+       dev_dbg(sst_drv_ctx->dev, "Enter: sync: %d\n", sync);
+       spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+       header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX);
+       if (sync) {
+               while (header.p.header_high.part.busy) {
+                       if (loop_count > 25) {
+                               dev_err(sst_drv_ctx->dev,
+                                       "sst: Busy wait failed, cant send this msg\n");
+                               retval = -EBUSY;
+                               goto out;
+                       }
+                       cpu_relax();
+                       loop_count++;
+                       header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX);
+               }
+       } else {
+               if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) {
+                       /* queue is empty, nothing to send */
+                       spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+                       dev_dbg(sst_drv_ctx->dev,
+                                       "Empty msg queue... NO Action\n");
+                       return 0;
+               }
+
+               if (header.p.header_high.part.busy) {
+                       spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+                       dev_dbg(sst_drv_ctx->dev, "Busy not free... post later\n");
+                       return 0;
+               }
+
+               /* copy msg from list */
+               msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next,
+                               struct ipc_post, node);
+               list_del(&msg->node);
+       }
+       dev_dbg(sst_drv_ctx->dev, "sst: Post message: header = %x\n",
+                               msg->mrfld_header.p.header_high.full);
+       dev_dbg(sst_drv_ctx->dev, "sst: size = 0x%x\n",
+                       msg->mrfld_header.p.header_low_payload);
+
+       if (msg->mrfld_header.p.header_high.part.large)
+               memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
+                       msg->mailbox_data,
+                       msg->mrfld_header.p.header_low_payload);
+
+       sst_shim_write64(sst_drv_ctx->shim, SST_IPCX, msg->mrfld_header.full);
+
+out:
+       spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+       kfree(msg->mailbox_data);
+       kfree(msg);
+       return retval;
+}
+
+void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
+{
+       union interrupt_reg_mrfld isr;
+       union interrupt_reg_mrfld imr;
+       union ipc_header_mrfld clear_ipc;
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+       imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX);
+       isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX);
+
+       /* write 1 to clear*/
+       isr.part.busy_interrupt = 1;
+       sst_shim_write64(sst_drv_ctx->shim, SST_ISRX, isr.full);
+
+       /* Set IA done bit */
+       clear_ipc.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCD);
+
+       clear_ipc.p.header_high.part.busy = 0;
+       clear_ipc.p.header_high.part.done = 1;
+       clear_ipc.p.header_low_payload = IPC_ACK_SUCCESS;
+       sst_shim_write64(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full);
+       /* un mask busy interrupt */
+       imr.part.busy_interrupt = 0;
+       sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full);
+       spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+}
+
+
+/*
+ * process_fw_init - process the FW init msg
+ *
+ * @msg: IPC message mailbox data from FW
+ *
+ * This function processes the FW init msg from FW
+ * marks FW state and prints debug info of loaded FW
+ */
+static void process_fw_init(struct intel_sst_drv *sst_drv_ctx,
+                       void *msg)
+{
+       struct ipc_header_fw_init *init =
+               (struct ipc_header_fw_init *)msg;
+       int retval = 0;
+
+       dev_dbg(sst_drv_ctx->dev, "*** FW Init msg came***\n");
+       if (init->result) {
+               sst_set_fw_state_locked(sst_drv_ctx, SST_RESET);
+               dev_err(sst_drv_ctx->dev, "FW Init failed, Error %x\n",
+                               init->result);
+               retval = init->result;
+               goto ret;
+       }
+
+ret:
+       sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0);
+}
+
+static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx,
+                       struct ipc_post *msg)
+{
+       u32 msg_id;
+       int str_id;
+       u32 data_size, i;
+       void *data_offset;
+       struct stream_info *stream;
+       union ipc_header_high msg_high;
+       u32 msg_low, pipe_id;
+
+       msg_high = msg->mrfld_header.p.header_high;
+       msg_low = msg->mrfld_header.p.header_low_payload;
+       msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id;
+       data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr));
+       data_size =  msg_low - (sizeof(struct ipc_dsp_hdr));
+
+       switch (msg_id) {
+       case IPC_SST_PERIOD_ELAPSED_MRFLD:
+               pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
+               str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
+               if (str_id > 0) {
+                       dev_dbg(sst_drv_ctx->dev,
+                               "Period elapsed rcvd for pipe id 0x%x\n",
+                               pipe_id);
+                       stream = &sst_drv_ctx->streams[str_id];
+                       if (stream->period_elapsed)
+                               stream->period_elapsed(stream->pcm_substream);
+                       if (stream->compr_cb)
+                               stream->compr_cb(stream->compr_cb_param);
+               }
+               break;
+
+       case IPC_IA_DRAIN_STREAM_MRFLD:
+               pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
+               str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
+               if (str_id > 0) {
+                       stream = &sst_drv_ctx->streams[str_id];
+                       if (stream->drain_notify)
+                               stream->drain_notify(stream->drain_cb_param);
+               }
+               break;
+
+       case IPC_IA_FW_ASYNC_ERR_MRFLD:
+               dev_err(sst_drv_ctx->dev, "FW sent async error msg:\n");
+               for (i = 0; i < (data_size/4); i++)
+                       print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE,
+                                       16, 4, data_offset, data_size, false);
+               break;
+
+       case IPC_IA_FW_INIT_CMPLT_MRFLD:
+               process_fw_init(sst_drv_ctx, data_offset);
+               break;
+
+       case IPC_IA_BUF_UNDER_RUN_MRFLD:
+               pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
+               str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
+               if (str_id > 0)
+                       dev_err(sst_drv_ctx->dev,
+                               "Buffer under-run for pipe:%#x str_id:%d\n",
+                               pipe_id, str_id);
+               break;
+
+       default:
+               dev_err(sst_drv_ctx->dev,
+                       "Unrecognized async msg from FW msg_id %#x\n", msg_id);
+       }
+}
+
+void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
+               struct ipc_post *msg)
+{
+       unsigned int drv_id;
+       void *data;
+       union ipc_header_high msg_high;
+       u32 msg_low;
+       struct ipc_dsp_hdr *dsp_hdr;
+       unsigned int cmd_id;
+
+       msg_high = msg->mrfld_header.p.header_high;
+       msg_low = msg->mrfld_header.p.header_low_payload;
+
+       dev_dbg(sst_drv_ctx->dev, "IPC process message header %x payload %x\n",
+                       msg->mrfld_header.p.header_high.full,
+                       msg->mrfld_header.p.header_low_payload);
+
+       drv_id = msg_high.part.drv_id;
+
+       /* Check for async messages first */
+       if (drv_id == SST_ASYNC_DRV_ID) {
+               /*FW sent async large message*/
+               process_fw_async_msg(sst_drv_ctx, msg);
+               return;
+       }
+
+       /* FW sent short error response for an IPC */
+       if (msg_high.part.result && drv_id && !msg_high.part.large) {
+               /* 32-bit FW error code in msg_low */
+               dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low);
+               sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
+                       msg_high.part.drv_id,
+                       msg_high.part.msg_id, NULL, 0);
+               return;
+       }
+
+       /*
+        * Process all valid responses
+        * if it is a large message, the payload contains the size to
+        * copy from mailbox
+        **/
+       if (msg_high.part.large) {
+               data = kzalloc(msg_low, GFP_KERNEL);
+               if (!data)
+                       return;
+               memcpy(data, (void *) msg->mailbox_data, msg_low);
+               /* Copy command id so that we can use to put sst to reset */
+               dsp_hdr = (struct ipc_dsp_hdr *)data;
+               cmd_id = dsp_hdr->cmd_id;
+               dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id);
+               if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
+                               msg_high.part.drv_id,
+                               msg_high.part.msg_id, data, msg_low))
+                       kfree(data);
+       } else {
+               sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
+                               msg_high.part.drv_id,
+                               msg_high.part.msg_id, NULL, 0);
+       }
+
+}
diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c
new file mode 100644 (file)
index 0000000..3391714
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ *  sst_dsp.c - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-14      Intel Corp
+ *  Authors:   Vinod Koul <vinod.koul@intel.com>
+ *             Harsha Priya <priya.harsha@intel.com>
+ *             Dharageswari R <dharageswari.r@intel.com>
+ *             KP Jeeja <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This file contains all dsp controlling functions like firmware download,
+ * setting/resetting dsp cores, etc
+ */
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/dmaengine.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../../common/sst-dsp.h"
+
+void memcpy32_toio(void __iomem *dst, const void *src, int count)
+{
+       /* __iowrite32_copy uses 32-bit count values so divide by 4 for
+        * right count in words
+        */
+       __iowrite32_copy(dst, src, count/4);
+}
+
+void memcpy32_fromio(void *dst, const void __iomem *src, int count)
+{
+       /* __iowrite32_copy uses 32-bit count values so divide by 4 for
+        * right count in words
+        */
+       __iowrite32_copy(dst, src, count/4);
+}
+
+/**
+ * intel_sst_reset_dsp_mrfld - Resetting SST DSP
+ *
+ * This resets DSP in case of MRFLD platfroms
+ */
+int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx)
+{
+       union config_status_reg_mrfld csr;
+
+       dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n");
+       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+
+       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+
+       csr.full |= 0x7;
+       sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
+       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+
+       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+
+       csr.full &= ~(0x1);
+       sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+       return 0;
+}
+
+/**
+ * sst_start_merrifield - Start the SST DSP processor
+ *
+ * This starts the DSP in MERRIFIELD platfroms
+ */
+int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx)
+{
+       union config_status_reg_mrfld csr;
+
+       dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n");
+       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+
+       csr.full |= 0x7;
+       sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+
+       csr.part.xt_snoop = 1;
+       csr.full &= ~(0x5);
+       sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+       dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n",
+                       csr.full);
+       return 0;
+}
+
+static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size,
+               struct fw_module_header **module, u32 *num_modules)
+{
+       struct sst_fw_header *header;
+       const void *sst_fw_in_mem = ctx->fw_in_mem;
+
+       dev_dbg(ctx->dev, "Enter\n");
+
+       /* Read the header information from the data pointer */
+       header = (struct sst_fw_header *)sst_fw_in_mem;
+       dev_dbg(ctx->dev,
+               "header sign=%s size=%x modules=%x fmt=%x size=%zx\n",
+               header->signature, header->file_size, header->modules,
+               header->file_format, sizeof(*header));
+
+       /* verify FW */
+       if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
+               (size != header->file_size + sizeof(*header))) {
+               /* Invalid FW signature */
+               dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n");
+               return -EINVAL;
+       }
+       *num_modules = header->modules;
+       *module = (void *)sst_fw_in_mem + sizeof(*header);
+
+       return 0;
+}
+
+/*
+ * sst_fill_memcpy_list - Fill the memcpy list
+ *
+ * @memcpy_list: List to be filled
+ * @destn: Destination addr to be filled in the list
+ * @src: Source addr to be filled in the list
+ * @size: Size to be filled in the list
+ *
+ * Adds the node to the list after required fields
+ * are populated in the node
+ */
+static int sst_fill_memcpy_list(struct list_head *memcpy_list,
+                       void *destn, const void *src, u32 size, bool is_io)
+{
+       struct sst_memcpy_list *listnode;
+
+       listnode = kzalloc(sizeof(*listnode), GFP_KERNEL);
+       if (listnode == NULL)
+               return -ENOMEM;
+       listnode->dstn = destn;
+       listnode->src = src;
+       listnode->size = size;
+       listnode->is_io = is_io;
+       list_add_tail(&listnode->memcpylist, memcpy_list);
+
+       return 0;
+}
+
+/**
+ * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list
+ *
+ * @sst_drv_ctx                : driver context
+ * @module             : FW module header
+ * @memcpy_list        : Pointer to the list to be populated
+ * Create the memcpy list as the number of block to be copied
+ * returns error or 0 if module sizes are proper
+ */
+static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx,
+               struct fw_module_header *module, struct list_head *memcpy_list)
+{
+       struct fw_block_info *block;
+       u32 count;
+       int ret_val = 0;
+       void __iomem *ram_iomem;
+
+       dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n",
+                       module->signature, module->mod_size,
+                       module->blocks, module->type);
+       dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point);
+
+       block = (void *)module + sizeof(*module);
+
+       for (count = 0; count < module->blocks; count++) {
+               if (block->size <= 0) {
+                       dev_err(sst_drv_ctx->dev, "block size invalid\n");
+                       return -EINVAL;
+               }
+               switch (block->type) {
+               case SST_IRAM:
+                       ram_iomem = sst_drv_ctx->iram;
+                       break;
+               case SST_DRAM:
+                       ram_iomem = sst_drv_ctx->dram;
+                       break;
+               case SST_DDR:
+                       ram_iomem = sst_drv_ctx->ddr;
+                       break;
+               case SST_CUSTOM_INFO:
+                       block = (void *)block + sizeof(*block) + block->size;
+                       continue;
+               default:
+                       dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n",
+                                       block->type, count);
+                       return -EINVAL;
+               }
+
+               ret_val = sst_fill_memcpy_list(memcpy_list,
+                               ram_iomem + block->ram_offset,
+                               (void *)block + sizeof(*block), block->size, 1);
+               if (ret_val)
+                       return ret_val;
+
+               block = (void *)block + sizeof(*block) + block->size;
+       }
+       return 0;
+}
+
+/**
+ * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy
+ *
+ * @ctx                        : pointer to drv context
+ * @size               : size of the firmware
+ * @fw_list            : pointer to list_head to be populated
+ * This function parses the FW image and saves the parsed image in the list
+ * for memcpy
+ */
+static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size,
+                               struct list_head *fw_list)
+{
+       struct fw_module_header *module;
+       u32 count, num_modules;
+       int ret_val;
+
+       ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules);
+       if (ret_val)
+               return ret_val;
+
+       for (count = 0; count < num_modules; count++) {
+               ret_val = sst_parse_module_memcpy(ctx, module, fw_list);
+               if (ret_val)
+                       return ret_val;
+               module = (void *)module + sizeof(*module) + module->mod_size;
+       }
+
+       return 0;
+}
+
+/**
+ * sst_do_memcpy - function initiates the memcpy
+ *
+ * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated
+ *
+ * Triggers the memcpy
+ */
+static void sst_do_memcpy(struct list_head *memcpy_list)
+{
+       struct sst_memcpy_list *listnode;
+
+       list_for_each_entry(listnode, memcpy_list, memcpylist) {
+               if (listnode->is_io == true)
+                       memcpy32_toio((void __iomem *)listnode->dstn,
+                                       listnode->src, listnode->size);
+               else
+                       memcpy(listnode->dstn, listnode->src, listnode->size);
+       }
+}
+
+void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx)
+{
+       struct sst_memcpy_list *listnode, *tmplistnode;
+
+       /* Free the list */
+       if (!list_empty(&sst_drv_ctx->memcpy_list)) {
+               list_for_each_entry_safe(listnode, tmplistnode,
+                               &sst_drv_ctx->memcpy_list, memcpylist) {
+                       list_del(&listnode->memcpylist);
+                       kfree(listnode);
+               }
+       }
+}
+
+static int sst_cache_and_parse_fw(struct intel_sst_drv *sst,
+               const struct firmware *fw)
+{
+       int retval = 0;
+
+       sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL);
+       if (!sst->fw_in_mem) {
+               retval = -ENOMEM;
+               goto end_release;
+       }
+       dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem);
+       dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem));
+       memcpy(sst->fw_in_mem, fw->data, fw->size);
+       retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list);
+       if (retval) {
+               dev_err(sst->dev, "Failed to parse fw\n");
+               kfree(sst->fw_in_mem);
+               sst->fw_in_mem = NULL;
+       }
+
+end_release:
+       release_firmware(fw);
+       return retval;
+
+}
+
+void sst_firmware_load_cb(const struct firmware *fw, void *context)
+{
+       struct intel_sst_drv *ctx = context;
+
+       dev_dbg(ctx->dev, "Enter\n");
+
+       if (fw == NULL) {
+               dev_err(ctx->dev, "request fw failed\n");
+               return;
+       }
+
+       mutex_lock(&ctx->sst_lock);
+
+       if (ctx->sst_state != SST_RESET ||
+                       ctx->fw_in_mem != NULL) {
+               release_firmware(fw);
+               mutex_unlock(&ctx->sst_lock);
+               return;
+       }
+
+       dev_dbg(ctx->dev, "Request Fw completed\n");
+       sst_cache_and_parse_fw(ctx, fw);
+       mutex_unlock(&ctx->sst_lock);
+}
+
+/*
+ * sst_request_fw - requests audio fw from kernel and saves a copy
+ *
+ * This function requests the SST FW from the kernel, parses it and
+ * saves a copy in the driver context
+ */
+static int sst_request_fw(struct intel_sst_drv *sst)
+{
+       int retval = 0;
+       const struct firmware *fw;
+
+       retval = request_firmware(&fw, sst->firmware_name, sst->dev);
+       if (fw == NULL) {
+               dev_err(sst->dev, "fw is returning as null\n");
+               return -EINVAL;
+       }
+       if (retval) {
+               dev_err(sst->dev, "request fw failed %d\n", retval);
+               return retval;
+       }
+       mutex_lock(&sst->sst_lock);
+       retval = sst_cache_and_parse_fw(sst, fw);
+       mutex_unlock(&sst->sst_lock);
+
+       return retval;
+}
+
+/*
+ * Writing the DDR physical base to DCCM offset
+ * so that FW can use it to setup TLB
+ */
+static void sst_dccm_config_write(void __iomem *dram_base,
+               unsigned int ddr_base)
+{
+       void __iomem *addr;
+       u32 bss_reset = 0;
+
+       addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET);
+       memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32));
+       bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT);
+       addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET);
+       memcpy32_toio(addr, &bss_reset, sizeof(u32));
+
+}
+
+void sst_post_download_mrfld(struct intel_sst_drv *ctx)
+{
+       sst_dccm_config_write(ctx->dram, ctx->ddr_base);
+       dev_dbg(ctx->dev, "config written to DCCM\n");
+}
+
+/**
+ * sst_load_fw - function to load FW into DSP
+ * Transfers the FW to DSP using dma/memcpy
+ */
+int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
+{
+       int ret_val = 0;
+       struct sst_block *block;
+
+       dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n");
+
+       if (sst_drv_ctx->sst_state !=  SST_RESET ||
+                       sst_drv_ctx->sst_state == SST_SHUTDOWN)
+               return -EAGAIN;
+
+       if (!sst_drv_ctx->fw_in_mem) {
+               dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n");
+               ret_val = sst_request_fw(sst_drv_ctx);
+               if (ret_val)
+                       return ret_val;
+       }
+
+       BUG_ON(!sst_drv_ctx->fw_in_mem);
+       block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID);
+       if (block == NULL)
+               return -ENOMEM;
+
+       /* Prevent C-states beyond C6 */
+       pm_qos_update_request(sst_drv_ctx->qos, 0);
+
+       sst_drv_ctx->sst_state = SST_FW_LOADING;
+
+       ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx);
+       if (ret_val)
+               goto restore;
+
+       sst_do_memcpy(&sst_drv_ctx->memcpy_list);
+
+       /* Write the DRAM/DCCM config before enabling FW */
+       if (sst_drv_ctx->ops->post_download)
+               sst_drv_ctx->ops->post_download(sst_drv_ctx);
+
+       /* bring sst out of reset */
+       ret_val = sst_drv_ctx->ops->start(sst_drv_ctx);
+       if (ret_val)
+               goto restore;
+
+       ret_val = sst_wait_timeout(sst_drv_ctx, block);
+       if (ret_val) {
+               dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val);
+               /* FW download failed due to timeout */
+               ret_val = -EBUSY;
+
+       }
+
+
+restore:
+       /* Re-enable Deeper C-states beyond C6 */
+       pm_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE);
+       sst_free_block(sst_drv_ctx, block);
+       dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n");
+
+       if (sst_drv_ctx->ops->restore_dsp_context)
+               sst_drv_ctx->ops->restore_dsp_context();
+       sst_drv_ctx->sst_state = SST_FW_RUNNING;
+       return ret_val;
+}
+
diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c
new file mode 100644 (file)
index 0000000..3a0b3bf
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ *  sst_pci.c - SST (LPE) driver init file for pci enumeration.
+ *
+ *  Copyright (C) 2008-14      Intel Corp
+ *  Authors:   Vinod Koul <vinod.koul@intel.com>
+ *             Harsha Priya <priya.harsha@intel.com>
+ *             Dharageswari R <dharageswari.r@intel.com>
+ *             KP Jeeja <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+
+static int sst_platform_get_resources(struct intel_sst_drv *ctx)
+{
+       int ddr_base, ret = 0;
+       struct pci_dev *pci = ctx->pci;
+
+       ret = pci_request_regions(pci, SST_DRV_NAME);
+       if (ret)
+               return ret;
+
+       /* map registers */
+       /* DDR base */
+       if (ctx->dev_id == SST_MRFLD_PCI_ID) {
+               ctx->ddr_base = pci_resource_start(pci, 0);
+               /* check that the relocated IMR base matches with FW Binary */
+               ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base);
+               if (!ctx->pdata->lib_info) {
+                       dev_err(ctx->dev, "lib_info pointer NULL\n");
+                       ret = -EINVAL;
+                       goto do_release_regions;
+               }
+               if (ddr_base != ctx->pdata->lib_info->mod_base) {
+                       dev_err(ctx->dev,
+                                       "FW LSP DDR BASE does not match with IFWI\n");
+                       ret = -EINVAL;
+                       goto do_release_regions;
+               }
+               ctx->ddr_end = pci_resource_end(pci, 0);
+
+               ctx->ddr = pcim_iomap(pci, 0,
+                                       pci_resource_len(pci, 0));
+               if (!ctx->ddr) {
+                       ret = -EINVAL;
+                       goto do_release_regions;
+               }
+               dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr);
+       } else {
+               ctx->ddr = NULL;
+       }
+       /* SHIM */
+       ctx->shim_phy_add = pci_resource_start(pci, 1);
+       ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1));
+       if (!ctx->shim) {
+               ret = -EINVAL;
+               goto do_release_regions;
+       }
+       dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim);
+
+       /* Shared SRAM */
+       ctx->mailbox_add = pci_resource_start(pci, 2);
+       ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2));
+       if (!ctx->mailbox) {
+               ret = -EINVAL;
+               goto do_release_regions;
+       }
+       dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox);
+
+       /* IRAM */
+       ctx->iram_end = pci_resource_end(pci, 3);
+       ctx->iram_base = pci_resource_start(pci, 3);
+       ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3));
+       if (!ctx->iram) {
+               ret = -EINVAL;
+               goto do_release_regions;
+       }
+       dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram);
+
+       /* DRAM */
+       ctx->dram_end = pci_resource_end(pci, 4);
+       ctx->dram_base = pci_resource_start(pci, 4);
+       ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4));
+       if (!ctx->dram) {
+               ret = -EINVAL;
+               goto do_release_regions;
+       }
+       dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram);
+do_release_regions:
+       pci_release_regions(pci);
+       return 0;
+}
+
+/*
+ * intel_sst_probe - PCI probe function
+ *
+ * @pci:       PCI device structure
+ * @pci_id: PCI device ID structure
+ *
+ */
+static int intel_sst_probe(struct pci_dev *pci,
+                       const struct pci_device_id *pci_id)
+{
+       int ret = 0;
+       struct intel_sst_drv *sst_drv_ctx;
+       struct sst_platform_info *sst_pdata = pci->dev.platform_data;
+
+       dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device);
+       ret = sst_alloc_drv_context(&sst_drv_ctx, &pci->dev, pci->device);
+       if (ret < 0)
+               return ret;
+
+       sst_drv_ctx->pdata = sst_pdata;
+       sst_drv_ctx->irq_num = pci->irq;
+       snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name),
+                       "%s%04x%s", "fw_sst_",
+                       sst_drv_ctx->dev_id, ".bin");
+
+       ret = sst_context_init(sst_drv_ctx);
+       if (ret < 0)
+               return ret;
+
+       /* Init the device */
+       ret = pcim_enable_device(pci);
+       if (ret) {
+               dev_err(sst_drv_ctx->dev,
+                       "device can't be enabled. Returned err: %d\n", ret);
+               goto do_free_drv_ctx;
+       }
+       sst_drv_ctx->pci = pci_dev_get(pci);
+       ret = sst_platform_get_resources(sst_drv_ctx);
+       if (ret < 0)
+               goto do_free_drv_ctx;
+
+       pci_set_drvdata(pci, sst_drv_ctx);
+       sst_configure_runtime_pm(sst_drv_ctx);
+
+       return ret;
+
+do_free_drv_ctx:
+       sst_context_cleanup(sst_drv_ctx);
+       dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
+       return ret;
+}
+
+/**
+ * intel_sst_remove - PCI remove function
+ *
+ * @pci:       PCI device structure
+ *
+ * This function is called by OS when a device is unloaded
+ * This frees the interrupt etc
+ */
+static void intel_sst_remove(struct pci_dev *pci)
+{
+       struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci);
+
+       sst_context_cleanup(sst_drv_ctx);
+       pci_dev_put(sst_drv_ctx->pci);
+       pci_release_regions(pci);
+       pci_set_drvdata(pci, NULL);
+}
+
+/* PCI Routines */
+static struct pci_device_id intel_sst_ids[] = {
+       { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
+       { 0, }
+};
+
+static struct pci_driver sst_driver = {
+       .name = SST_DRV_NAME,
+       .id_table = intel_sst_ids,
+       .probe = intel_sst_probe,
+       .remove = intel_sst_remove,
+#ifdef CONFIG_PM
+       .driver = {
+               .pm = &intel_sst_pm,
+       },
+#endif
+};
+
+module_pci_driver(sst_driver);
+
+MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
+MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("sst");
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c
new file mode 100644 (file)
index 0000000..adb32fe
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ *  sst_pvt.c - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-14      Intel Corp
+ *  Authors:   Vinod Koul <vinod.koul@intel.com>
+ *             Harsha Priya <priya.harsha@intel.com>
+ *             Dharageswari R <dharageswari.r@intel.com>
+ *             KP Jeeja <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kobject.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <sound/asound.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../../common/sst-dsp.h"
+
+int sst_shim_write(void __iomem *addr, int offset, int value)
+{
+       writel(value, addr + offset);
+       return 0;
+}
+
+u32 sst_shim_read(void __iomem *addr, int offset)
+{
+       return readl(addr + offset);
+}
+
+u64 sst_reg_read64(void __iomem *addr, int offset)
+{
+       u64 val = 0;
+
+       memcpy_fromio(&val, addr + offset, sizeof(val));
+
+       return val;
+}
+
+int sst_shim_write64(void __iomem *addr, int offset, u64 value)
+{
+       memcpy_toio(addr + offset, &value, sizeof(value));
+       return 0;
+}
+
+u64 sst_shim_read64(void __iomem *addr, int offset)
+{
+       u64 val = 0;
+
+       memcpy_fromio(&val, addr + offset, sizeof(val));
+       return val;
+}
+
+void sst_set_fw_state_locked(
+               struct intel_sst_drv *sst_drv_ctx, int sst_state)
+{
+       mutex_lock(&sst_drv_ctx->sst_lock);
+       sst_drv_ctx->sst_state = sst_state;
+       mutex_unlock(&sst_drv_ctx->sst_lock);
+}
+
+/*
+ * sst_wait_interruptible - wait on event
+ *
+ * @sst_drv_ctx: Driver context
+ * @block: Driver block to wait on
+ *
+ * This function waits without a timeout (and is interruptable) for a
+ * given block event
+ */
+int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
+                               struct sst_block *block)
+{
+       int retval = 0;
+
+       if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
+                               block->condition)) {
+               /* event wake */
+               if (block->ret_code < 0) {
+                       dev_err(sst_drv_ctx->dev,
+                               "stream failed %d\n", block->ret_code);
+                       retval = -EBUSY;
+               } else {
+                       dev_dbg(sst_drv_ctx->dev, "event up\n");
+                       retval = 0;
+               }
+       } else {
+               dev_err(sst_drv_ctx->dev, "signal interrupted\n");
+               retval = -EINTR;
+       }
+       return retval;
+
+}
+
+/*
+ * sst_wait_timeout - wait on event for timeout
+ *
+ * @sst_drv_ctx: Driver context
+ * @block: Driver block to wait on
+ *
+ * This function waits with a timeout value (and is not interruptible) on a
+ * given block event
+ */
+int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, struct sst_block *block)
+{
+       int retval = 0;
+
+       /*
+        * NOTE:
+        * Observed that FW processes the alloc msg and replies even
+        * before the alloc thread has finished execution
+        */
+       dev_dbg(sst_drv_ctx->dev,
+               "waiting for condition %x ipc %d drv_id %d\n",
+               block->condition, block->msg_id, block->drv_id);
+       if (wait_event_timeout(sst_drv_ctx->wait_queue,
+                               block->condition,
+                               msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
+               /* event wake */
+               dev_dbg(sst_drv_ctx->dev, "Event wake %x\n",
+                               block->condition);
+               dev_dbg(sst_drv_ctx->dev, "message ret: %d\n",
+                               block->ret_code);
+               retval = -block->ret_code;
+       } else {
+               block->on = false;
+               dev_err(sst_drv_ctx->dev,
+                       "Wait timed-out condition:%#x, msg_id:%#x fw_state %#x\n",
+                       block->condition, block->msg_id, sst_drv_ctx->sst_state);
+               sst_drv_ctx->sst_state = SST_RESET;
+
+               retval = -EBUSY;
+       }
+       return retval;
+}
+
+/*
+ * sst_create_ipc_msg - create a IPC message
+ *
+ * @arg: ipc message
+ * @large: large or short message
+ *
+ * this function allocates structures to send a large or short
+ * message to the firmware
+ */
+int sst_create_ipc_msg(struct ipc_post **arg, bool large)
+{
+       struct ipc_post *msg;
+
+       msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
+       if (!msg)
+               return -ENOMEM;
+       if (large) {
+               msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
+               if (!msg->mailbox_data) {
+                       kfree(msg);
+                       return -ENOMEM;
+               }
+       } else {
+               msg->mailbox_data = NULL;
+       }
+       msg->is_large = large;
+       *arg = msg;
+       return 0;
+}
+
+/*
+ * sst_create_block_and_ipc_msg - Creates IPC message and sst block
+ * @arg: passed to sst_create_ipc_message API
+ * @large: large or short message
+ * @sst_drv_ctx: sst driver context
+ * @block: return block allocated
+ * @msg_id: IPC
+ * @drv_id: stream id or private id
+ */
+int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large,
+               struct intel_sst_drv *sst_drv_ctx, struct sst_block **block,
+               u32 msg_id, u32 drv_id)
+{
+       int retval = 0;
+
+       retval = sst_create_ipc_msg(arg, large);
+       if (retval)
+               return retval;
+       *block = sst_create_block(sst_drv_ctx, msg_id, drv_id);
+       if (*block == NULL) {
+               kfree(*arg);
+               return -ENOMEM;
+       }
+       return retval;
+}
+
+/*
+ * sst_clean_stream - clean the stream context
+ *
+ * @stream: stream structure
+ *
+ * this function resets the stream contexts
+ * should be called in free
+ */
+void sst_clean_stream(struct stream_info *stream)
+{
+       stream->status = STREAM_UN_INIT;
+       stream->prev = STREAM_UN_INIT;
+       mutex_lock(&stream->lock);
+       stream->cumm_bytes = 0;
+       mutex_unlock(&stream->lock);
+}
+
+int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
+               int task_id, int ipc_msg, int cmd_id, int pipe_id,
+               size_t mbox_data_len, const void *mbox_data, void **data,
+               bool large, bool fill_dsp, bool sync, bool response)
+{
+       struct ipc_post *msg = NULL;
+       struct ipc_dsp_hdr dsp_hdr;
+       struct sst_block *block;
+       int ret = 0, pvt_id;
+
+       pvt_id = sst_assign_pvt_id(sst);
+       if (pvt_id < 0)
+               return pvt_id;
+
+       if (response)
+               ret = sst_create_block_and_ipc_msg(
+                               &msg, large, sst, &block, ipc_msg, pvt_id);
+       else
+               ret = sst_create_ipc_msg(&msg, large);
+
+       if (ret < 0) {
+               test_and_clear_bit(pvt_id, &sst->pvt_id);
+               return -ENOMEM;
+       }
+
+       dev_dbg(sst->dev, "pvt_id = %d, pipe id = %d, task = %d ipc_msg: %d\n",
+                pvt_id, pipe_id, task_id, ipc_msg);
+       sst_fill_header_mrfld(&msg->mrfld_header, ipc_msg,
+                                       task_id, large, pvt_id);
+       msg->mrfld_header.p.header_low_payload = sizeof(dsp_hdr) + mbox_data_len;
+       msg->mrfld_header.p.header_high.part.res_rqd = !sync;
+       dev_dbg(sst->dev, "header:%x\n",
+                       msg->mrfld_header.p.header_high.full);
+       dev_dbg(sst->dev, "response rqd: %x",
+                       msg->mrfld_header.p.header_high.part.res_rqd);
+       dev_dbg(sst->dev, "msg->mrfld_header.p.header_low_payload:%d",
+                       msg->mrfld_header.p.header_low_payload);
+       if (fill_dsp) {
+               sst_fill_header_dsp(&dsp_hdr, cmd_id, pipe_id, mbox_data_len);
+               memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr));
+               if (mbox_data_len) {
+                       memcpy(msg->mailbox_data + sizeof(dsp_hdr),
+                                       mbox_data, mbox_data_len);
+               }
+       }
+
+       if (sync)
+               sst->ops->post_message(sst, msg, true);
+       else
+               sst_add_to_dispatch_list_and_post(sst, msg);
+
+       if (response) {
+               ret = sst_wait_timeout(sst, block);
+               if (ret < 0) {
+                       goto out;
+               } else if(block->data) {
+                       if (!data)
+                               goto out;
+                       *data = kzalloc(block->size, GFP_KERNEL);
+                       if (!(*data)) {
+                               ret = -ENOMEM;
+                               goto out;
+                       } else
+                               memcpy(data, (void *) block->data, block->size);
+               }
+       }
+out:
+       if (response)
+               sst_free_block(sst, block);
+       test_and_clear_bit(pvt_id, &sst->pvt_id);
+       return ret;
+}
+
+int sst_pm_runtime_put(struct intel_sst_drv *sst_drv)
+{
+       int ret;
+
+       pm_runtime_mark_last_busy(sst_drv->dev);
+       ret = pm_runtime_put_autosuspend(sst_drv->dev);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+void sst_fill_header_mrfld(union ipc_header_mrfld *header,
+                               int msg, int task_id, int large, int drv_id)
+{
+       header->full = 0;
+       header->p.header_high.part.msg_id = msg;
+       header->p.header_high.part.task_id = task_id;
+       header->p.header_high.part.large = large;
+       header->p.header_high.part.drv_id = drv_id;
+       header->p.header_high.part.done = 0;
+       header->p.header_high.part.busy = 1;
+       header->p.header_high.part.res_rqd = 1;
+}
+
+void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg,
+                                       int pipe_id, int len)
+{
+       dsp->cmd_id = msg;
+       dsp->mod_index_id = 0xff;
+       dsp->pipe_id = pipe_id;
+       dsp->length = len;
+       dsp->mod_id = 0;
+}
+
+#define SST_MAX_BLOCKS 15
+/*
+ * sst_assign_pvt_id - assign a pvt id for stream
+ *
+ * @sst_drv_ctx : driver context
+ *
+ * this function assigns a private id for calls that dont have stream
+ * context yet, should be called with lock held
+ * uses bits for the id, and finds first free bits and assigns that
+ */
+int sst_assign_pvt_id(struct intel_sst_drv *drv)
+{
+       int local;
+
+       spin_lock(&drv->block_lock);
+       /* find first zero index from lsb */
+       local = ffz(drv->pvt_id);
+       dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local);
+       if (local >= SST_MAX_BLOCKS){
+               spin_unlock(&drv->block_lock);
+               dev_err(drv->dev, "PVT _ID error: no free id blocks ");
+               return -EINVAL;
+       }
+       /* toggle the index */
+       change_bit(local, &drv->pvt_id);
+       spin_unlock(&drv->block_lock);
+       return local;
+}
+
+void sst_init_stream(struct stream_info *stream,
+               int codec, int sst_id, int ops, u8 slot)
+{
+       stream->status = STREAM_INIT;
+       stream->prev = STREAM_UN_INIT;
+       stream->ops = ops;
+}
+
+int sst_validate_strid(
+               struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+       if (str_id <= 0 || str_id > sst_drv_ctx->info.max_streams) {
+               dev_err(sst_drv_ctx->dev,
+                       "SST ERR: invalid stream id : %d, max %d\n",
+                       str_id, sst_drv_ctx->info.max_streams);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+struct stream_info *get_stream_info(
+               struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+       if (sst_validate_strid(sst_drv_ctx, str_id))
+               return NULL;
+       return &sst_drv_ctx->streams[str_id];
+}
+
+int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx,
+               u32 pipe_id)
+{
+       int i;
+
+       for (i = 1; i <= sst_drv_ctx->info.max_streams; i++)
+               if (pipe_id == sst_drv_ctx->streams[i].pipe_id)
+                       return i;
+
+       dev_dbg(sst_drv_ctx->dev, "no such pipe_id(%u)", pipe_id);
+       return -1;
+}
+
+u32 relocate_imr_addr_mrfld(u32 base_addr)
+{
+       /* Get the difference from 512MB aligned base addr */
+       /* relocate the base */
+       base_addr = MRFLD_FW_VIRTUAL_BASE + (base_addr % (512 * 1024 * 1024));
+       return base_addr;
+}
+EXPORT_SYMBOL_GPL(relocate_imr_addr_mrfld);
+
+void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst,
+                                               struct ipc_post *msg)
+{
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&sst->ipc_spin_lock, irq_flags);
+       list_add_tail(&msg->node, &sst->ipc_dispatch_list);
+       spin_unlock_irqrestore(&sst->ipc_spin_lock, irq_flags);
+       sst->ops->post_message(sst, NULL, false);
+}
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
new file mode 100644 (file)
index 0000000..a74c64c
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ *  sst_stream.c - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-14 Intel Corp
+ *  Authors:   Vinod Koul <vinod.koul@intel.com>
+ *             Harsha Priya <priya.harsha@intel.com>
+ *             Dharageswari R <dharageswari.r@intel.com>
+ *             KP Jeeja <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../../common/sst-dsp.h"
+
+int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
+{
+       struct snd_sst_alloc_mrfld alloc_param;
+       struct snd_sst_params *str_params;
+       struct snd_sst_tstamp fw_tstamp;
+       struct stream_info *str_info;
+       struct snd_sst_alloc_response *response;
+       unsigned int str_id, pipe_id, task_id;
+       int i, num_ch, ret = 0;
+       void *data = NULL;
+
+       dev_dbg(sst_drv_ctx->dev, "Enter\n");
+       BUG_ON(!params);
+
+       str_params = (struct snd_sst_params *)params;
+       memset(&alloc_param, 0, sizeof(alloc_param));
+       alloc_param.operation = str_params->ops;
+       alloc_param.codec_type = str_params->codec;
+       alloc_param.sg_count = str_params->aparams.sg_count;
+       alloc_param.ring_buf_info[0].addr =
+               str_params->aparams.ring_buf_info[0].addr;
+       alloc_param.ring_buf_info[0].size =
+               str_params->aparams.ring_buf_info[0].size;
+       alloc_param.frag_size = str_params->aparams.frag_size;
+
+       memcpy(&alloc_param.codec_params, &str_params->sparams,
+                       sizeof(struct snd_sst_stream_params));
+
+       /*
+        * fill channel map params for multichannel support.
+        * Ideally channel map should be received from upper layers
+        * for multichannel support.
+        * Currently hardcoding as per FW reqm.
+        */
+       num_ch = sst_get_num_channel(str_params);
+       for (i = 0; i < 8; i++) {
+               if (i < num_ch)
+                       alloc_param.codec_params.uc.pcm_params.channel_map[i] = i;
+               else
+                       alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF;
+       }
+
+       str_id = str_params->stream_id;
+       str_info = get_stream_info(sst_drv_ctx, str_id);
+       if (str_info == NULL) {
+               dev_err(sst_drv_ctx->dev, "get stream info returned null\n");
+               return -EINVAL;
+       }
+
+       pipe_id = str_params->device_type;
+       task_id = str_params->task;
+       sst_drv_ctx->streams[str_id].pipe_id = pipe_id;
+       sst_drv_ctx->streams[str_id].task_id = task_id;
+       sst_drv_ctx->streams[str_id].num_ch = num_ch;
+
+       if (sst_drv_ctx->info.lpe_viewpt_rqd)
+               alloc_param.ts = sst_drv_ctx->info.mailbox_start +
+                       sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
+       else
+               alloc_param.ts = sst_drv_ctx->mailbox_add +
+                       sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
+
+       dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n",
+                       alloc_param.ts);
+       dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
+                       pipe_id, task_id);
+
+       /* allocate device type context */
+       sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type,
+                       str_id, alloc_param.operation, 0);
+
+       dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
+                       str_id, pipe_id);
+       ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,
+                       IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param),
+                       &alloc_param, data, true, true, false, true);
+
+       if (ret < 0) {
+               dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
+               /* alloc failed, so reset the state to uninit */
+               str_info->status = STREAM_UN_INIT;
+               str_id = ret;
+       } else if (data) {
+               response = (struct snd_sst_alloc_response *)data;
+               ret = response->str_type.result;
+               if (!ret)
+                       goto out;
+               dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
+               if (ret == SST_ERR_STREAM_IN_USE) {
+                       dev_err(sst_drv_ctx->dev,
+                               "FW not in clean state, send free for:%d\n", str_id);
+                       sst_free_stream(sst_drv_ctx, str_id);
+               }
+               str_id = -ret;
+       }
+out:
+       kfree(data);
+       return str_id;
+}
+
+/**
+* sst_start_stream - Send msg for a starting stream
+* @str_id:      stream ID
+*
+* This function is called by any function which wants to start
+* a stream.
+*/
+int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+       int retval = 0;
+       struct stream_info *str_info;
+       u16 data = 0;
+
+       dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id);
+       str_info = get_stream_info(sst_drv_ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       if (str_info->status != STREAM_RUNNING)
+               return -EBADRQC;
+
+       retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
+                       IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id,
+                       sizeof(u16), &data, NULL, true, true, true, false);
+
+       return retval;
+}
+
+int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
+               struct snd_sst_bytes_v2 *bytes)
+{      struct ipc_post *msg = NULL;
+       u32 length;
+       int pvt_id, ret = 0;
+       struct sst_block *block = NULL;
+
+       dev_dbg(sst_drv_ctx->dev,
+               "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
+               bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
+               bytes->pipe_id, bytes->len);
+
+       if (sst_create_ipc_msg(&msg, true))
+               return -ENOMEM;
+
+       pvt_id = sst_assign_pvt_id(sst_drv_ctx);
+       sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
+                       bytes->task_id, 1, pvt_id);
+       msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
+       length = bytes->len;
+       msg->mrfld_header.p.header_low_payload = length;
+       dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
+       memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
+       if (bytes->block) {
+               block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
+               if (block == NULL) {
+                       kfree(msg);
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg);
+       dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
+                       msg->mrfld_header.p.header_low_payload);
+
+       if (bytes->block) {
+               ret = sst_wait_timeout(sst_drv_ctx, block);
+               if (ret) {
+                       dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
+                       sst_free_block(sst_drv_ctx, block);
+                       goto out;
+               }
+       }
+       if (bytes->type == SND_SST_BYTES_GET) {
+               /*
+                * copy the reply and send back
+                * we need to update only sz and payload
+                */
+               if (bytes->block) {
+                       unsigned char *r = block->data;
+
+                       dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
+                                       bytes->len);
+                       memcpy(bytes->bytes, r, bytes->len);
+               }
+       }
+       if (bytes->block)
+               sst_free_block(sst_drv_ctx, block);
+out:
+       test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
+       return 0;
+}
+
+/*
+ * sst_pause_stream - Send msg for a pausing stream
+ * @str_id:     stream ID
+ *
+ * This function is called by any function which wants to pause
+ * an already running stream.
+ */
+int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+       int retval = 0;
+       struct stream_info *str_info;
+
+       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id);
+       str_info = get_stream_info(sst_drv_ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       if (str_info->status == STREAM_PAUSED)
+               return 0;
+       if (str_info->status == STREAM_RUNNING ||
+               str_info->status == STREAM_INIT) {
+               if (str_info->prev == STREAM_UN_INIT)
+                       return -EBADRQC;
+
+               retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
+                               IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
+                               0, NULL, NULL, true, true, false, true);
+
+               if (retval == 0) {
+                       str_info->prev = str_info->status;
+                       str_info->status = STREAM_PAUSED;
+               } else if (retval == SST_ERR_INVALID_STREAM_ID) {
+                       retval = -EINVAL;
+                       mutex_lock(&sst_drv_ctx->sst_lock);
+                       sst_clean_stream(str_info);
+                       mutex_unlock(&sst_drv_ctx->sst_lock);
+               }
+       } else {
+               retval = -EBADRQC;
+               dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n ");
+       }
+
+       return retval;
+}
+
+/**
+ * sst_resume_stream - Send msg for resuming stream
+ * @str_id:            stream ID
+ *
+ * This function is called by any function which wants to resume
+ * an already paused stream.
+ */
+int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+       int retval = 0;
+       struct stream_info *str_info;
+
+       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id);
+       str_info = get_stream_info(sst_drv_ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       if (str_info->status == STREAM_RUNNING)
+                       return 0;
+       if (str_info->status == STREAM_PAUSED) {
+               retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
+                               IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
+                               str_info->pipe_id, 0, NULL, NULL,
+                               true, true, false, true);
+
+               if (!retval) {
+                       if (str_info->prev == STREAM_RUNNING)
+                               str_info->status = STREAM_RUNNING;
+                       else
+                               str_info->status = STREAM_INIT;
+                       str_info->prev = STREAM_PAUSED;
+               } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
+                       retval = -EINVAL;
+                       mutex_lock(&sst_drv_ctx->sst_lock);
+                       sst_clean_stream(str_info);
+                       mutex_unlock(&sst_drv_ctx->sst_lock);
+               }
+       } else {
+               retval = -EBADRQC;
+               dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n");
+       }
+
+       return retval;
+}
+
+
+/**
+ * sst_drop_stream - Send msg for stopping stream
+ * @str_id:            stream ID
+ *
+ * This function is called by any function which wants to stop
+ * a stream.
+ */
+int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+       int retval = 0;
+       struct stream_info *str_info;
+
+       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id);
+       str_info = get_stream_info(sst_drv_ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+
+       if (str_info->status != STREAM_UN_INIT) {
+               str_info->prev = STREAM_UN_INIT;
+               str_info->status = STREAM_INIT;
+               str_info->cumm_bytes = 0;
+               retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
+                               IPC_CMD, IPC_IA_DROP_STREAM_MRFLD,
+                               str_info->pipe_id, 0, NULL, NULL,
+                               true, true, true, false);
+       } else {
+               retval = -EBADRQC;
+               dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
+                               str_info->status);
+       }
+       return retval;
+}
+
+/**
+* sst_drain_stream - Send msg for draining stream
+* @str_id:             stream ID
+*
+* This function is called by any function which wants to drain
+* a stream.
+*/
+int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
+                       int str_id, bool partial_drain)
+{
+       int retval = 0;
+       struct stream_info *str_info;
+
+       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id);
+       str_info = get_stream_info(sst_drv_ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       if (str_info->status != STREAM_RUNNING &&
+               str_info->status != STREAM_INIT &&
+               str_info->status != STREAM_PAUSED) {
+                       dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n",
+                                      str_info->status);
+                       return -EBADRQC;
+       }
+
+       retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
+                       IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id,
+                       sizeof(u8), &partial_drain, NULL, true, true, false, false);
+       /*
+        * with new non blocked drain implementation in core we dont need to
+        * wait for respsonse, and need to only invoke callback for drain
+        * complete
+        */
+
+       return retval;
+}
+
+/**
+ * sst_free_stream - Frees a stream
+ * @str_id:            stream ID
+ *
+ * This function is called by any function which wants to free
+ * a stream.
+ */
+int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+       int retval = 0;
+       struct stream_info *str_info;
+       struct intel_sst_ops *ops;
+
+       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
+
+       mutex_lock(&sst_drv_ctx->sst_lock);
+       if (sst_drv_ctx->sst_state == SST_RESET) {
+               mutex_unlock(&sst_drv_ctx->sst_lock);
+               return -ENODEV;
+       }
+       mutex_unlock(&sst_drv_ctx->sst_lock);
+       str_info = get_stream_info(sst_drv_ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       ops = sst_drv_ctx->ops;
+
+       mutex_lock(&str_info->lock);
+       if (str_info->status != STREAM_UN_INIT) {
+               str_info->prev =  str_info->status;
+               str_info->status = STREAM_UN_INIT;
+               mutex_unlock(&str_info->lock);
+
+               dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
+                               str_id, str_info->pipe_id);
+               retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
+                               IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
+                               NULL, NULL, true, true, false, true);
+
+               dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n",
+                               retval);
+               mutex_lock(&sst_drv_ctx->sst_lock);
+               sst_clean_stream(str_info);
+               mutex_unlock(&sst_drv_ctx->sst_lock);
+               dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n");
+       } else {
+               mutex_unlock(&str_info->lock);
+               retval = -EBADRQC;
+               dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n");
+       }
+
+       return retval;
+}
diff --git a/sound/soc/intel/baytrail/Makefile b/sound/soc/intel/baytrail/Makefile
new file mode 100644 (file)
index 0000000..488408c
--- /dev/null
@@ -0,0 +1,4 @@
+snd-soc-sst-baytrail-pcm-objs := \
+               sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o
+
+obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
diff --git a/sound/soc/intel/baytrail/sst-baytrail-dsp.c b/sound/soc/intel/baytrail/sst-baytrail-dsp.c
new file mode 100644 (file)
index 0000000..01d023c
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Intel Baytrail SST DSP driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "sst-baytrail-ipc.h"
+
+#define SST_BYT_FW_SIGNATURE_SIZE      4
+#define SST_BYT_FW_SIGN                        "$SST"
+
+#define SST_BYT_IRAM_OFFSET    0xC0000
+#define SST_BYT_DRAM_OFFSET    0x100000
+#define SST_BYT_SHIM_OFFSET    0x140000
+
+enum sst_ram_type {
+       SST_BYT_IRAM    = 1,
+       SST_BYT_DRAM    = 2,
+       SST_BYT_CACHE   = 3,
+};
+
+struct dma_block_info {
+       enum sst_ram_type       type;   /* IRAM/DRAM */
+       u32                     size;   /* Bytes */
+       u32                     ram_offset; /* Offset in I/DRAM */
+       u32                     rsvd;   /* Reserved field */
+};
+
+struct fw_header {
+       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
+       u32 file_size; /* size of fw minus this header */
+       u32 modules; /*  # of modules */
+       u32 file_format; /* version of header format */
+       u32 reserved[4];
+};
+
+struct sst_byt_fw_module_header {
+       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
+       u32 mod_size; /* size of module */
+       u32 blocks; /* # of blocks */
+       u32 type; /* codec type, pp lib */
+       u32 entry_point;
+};
+
+static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
+                               struct sst_byt_fw_module_header *module)
+{
+       struct dma_block_info *block;
+       struct sst_module *mod;
+       struct sst_module_template template;
+       int count;
+
+       memset(&template, 0, sizeof(template));
+       template.id = module->type;
+       template.entry = module->entry_point;
+
+       mod = sst_module_new(fw, &template, NULL);
+       if (mod == NULL)
+               return -ENOMEM;
+
+       block = (void *)module + sizeof(*module);
+
+       for (count = 0; count < module->blocks; count++) {
+
+               if (block->size <= 0) {
+                       dev_err(dsp->dev, "block %d size invalid\n", count);
+                       return -EINVAL;
+               }
+
+               switch (block->type) {
+               case SST_BYT_IRAM:
+                       mod->offset = block->ram_offset +
+                                           dsp->addr.iram_offset;
+                       mod->type = SST_MEM_IRAM;
+                       break;
+               case SST_BYT_DRAM:
+                       mod->offset = block->ram_offset +
+                                           dsp->addr.dram_offset;
+                       mod->type = SST_MEM_DRAM;
+                       break;
+               case SST_BYT_CACHE:
+                       mod->offset = block->ram_offset +
+                                           (dsp->addr.fw_ext - dsp->addr.lpe);
+                       mod->type = SST_MEM_CACHE;
+                       break;
+               default:
+                       dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
+                               block->type, count);
+                       return -EINVAL;
+               }
+
+               mod->size = block->size;
+               mod->data = (void *)block + sizeof(*block);
+
+               sst_module_alloc_blocks(mod);
+
+               block = (void *)block + sizeof(*block) + block->size;
+       }
+       return 0;
+}
+
+static int sst_byt_parse_fw_image(struct sst_fw *sst_fw)
+{
+       struct fw_header *header;
+       struct sst_byt_fw_module_header *module;
+       struct sst_dsp *dsp = sst_fw->dsp;
+       int ret, count;
+
+       /* Read the header information from the data pointer */
+       header = (struct fw_header *)sst_fw->dma_buf;
+
+       /* verify FW */
+       if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) ||
+           (sst_fw->size != header->file_size + sizeof(*header))) {
+               /* Invalid FW signature */
+               dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dsp->dev,
+               "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
+               header->signature, header->file_size, header->modules,
+               header->file_format, sizeof(*header));
+
+       module = (void *)sst_fw->dma_buf + sizeof(*header);
+       for (count = 0; count < header->modules; count++) {
+               /* module */
+               ret = sst_byt_parse_module(dsp, sst_fw, module);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "invalid module %d\n", count);
+                       return ret;
+               }
+               module = (void *)module + sizeof(*module) + module->mod_size;
+       }
+
+       return 0;
+}
+
+static void sst_byt_dump_shim(struct sst_dsp *sst)
+{
+       int i;
+       u64 reg;
+
+       for (i = 0; i <= 0xF0; i += 8) {
+               reg = sst_dsp_shim_read64_unlocked(sst, i);
+               if (reg)
+                       dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n",
+                               i, reg);
+       }
+
+       for (i = 0x00; i <= 0xff; i += 4) {
+               reg = readl(sst->addr.pci_cfg + i);
+               if (reg)
+                       dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n",
+                               i, (u32)reg);
+       }
+}
+
+static irqreturn_t sst_byt_irq(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       u64 isrx;
+       irqreturn_t ret = IRQ_NONE;
+
+       spin_lock(&sst->spinlock);
+
+       isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
+       if (isrx & SST_ISRX_DONE) {
+               /* ADSP has processed the message request from IA */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX,
+                                                   SST_BYT_IPCX_DONE, 0);
+               ret = IRQ_WAKE_THREAD;
+       }
+       if (isrx & SST_BYT_ISRX_REQUEST) {
+               /* mask message request from ADSP and do processing later */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
+                                                   SST_BYT_IMRX_REQUEST,
+                                                   SST_BYT_IMRX_REQUEST);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       spin_unlock(&sst->spinlock);
+
+       return ret;
+}
+
+static void sst_byt_boot(struct sst_dsp *sst)
+{
+       int tries = 10;
+
+       /*
+        * save the physical address of extended firmware block in the first
+        * 4 bytes of the mailbox
+        */
+       memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
+              &sst->pdata->fw_base, sizeof(u32));
+
+       /* release stall and wait to unstall */
+       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
+       while (tries--) {
+               if (!(sst_dsp_shim_read64(sst, SST_CSR) &
+                     SST_BYT_CSR_PWAITMODE))
+                       break;
+               msleep(100);
+       }
+       if (tries < 0) {
+               dev_err(sst->dev, "unable to start DSP\n");
+               sst_byt_dump_shim(sst);
+       }
+}
+
+static void sst_byt_reset(struct sst_dsp *sst)
+{
+       /* put DSP into reset, set reset vector and stall */
+       sst_dsp_shim_update_bits64(sst, SST_CSR,
+               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL,
+               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL);
+
+       udelay(10);
+
+       /* take DSP out of reset and keep stalled for FW loading */
+       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0);
+}
+
+struct sst_adsp_memregion {
+       u32 start;
+       u32 end;
+       int blocks;
+       enum sst_mem_type type;
+};
+
+/* BYT test stuff */
+static const struct sst_adsp_memregion byt_region[] = {
+       {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */
+       {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+};
+
+static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       sst->addr.lpe_base = pdata->lpe_base;
+       sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
+       if (!sst->addr.lpe)
+               return -ENODEV;
+
+       /* ADSP PCI MMIO config space */
+       sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
+       if (!sst->addr.pci_cfg) {
+               iounmap(sst->addr.lpe);
+               return -ENODEV;
+       }
+
+       /* SST Extended FW allocation */
+       sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size);
+       if (!sst->addr.fw_ext) {
+               iounmap(sst->addr.pci_cfg);
+               iounmap(sst->addr.lpe);
+               return -ENODEV;
+       }
+
+       /* SST Shim */
+       sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
+
+       sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204,
+                            SST_BYT_IPC_MAX_PAYLOAD_SIZE,
+                            SST_BYT_MAILBOX_OFFSET,
+                            SST_BYT_IPC_MAX_PAYLOAD_SIZE);
+
+       sst->irq = pdata->irq;
+
+       return 0;
+}
+
+static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       const struct sst_adsp_memregion *region;
+       struct device *dev;
+       int ret = -ENODEV, i, j, region_count;
+       u32 offset, size;
+
+       dev = sst->dev;
+
+       switch (sst->id) {
+       case SST_DEV_ID_BYT:
+               region = byt_region;
+               region_count = ARRAY_SIZE(byt_region);
+               sst->addr.iram_offset = SST_BYT_IRAM_OFFSET;
+               sst->addr.dram_offset = SST_BYT_DRAM_OFFSET;
+               sst->addr.shim_offset = SST_BYT_SHIM_OFFSET;
+               break;
+       default:
+               dev_err(dev, "failed to get mem resources\n");
+               return ret;
+       }
+
+       ret = sst_byt_resource_map(sst, pdata);
+       if (ret < 0) {
+               dev_err(dev, "failed to map resources\n");
+               return ret;
+       }
+
+       ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       /* enable Interrupt from both sides */
+       sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0);
+       sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0);
+
+       /* register DSP memory blocks - ideally we should get this from ACPI */
+       for (i = 0; i < region_count; i++) {
+               offset = region[i].start;
+               size = (region[i].end - region[i].start) / region[i].blocks;
+
+               /* register individual memory blocks */
+               for (j = 0; j < region[i].blocks; j++) {
+                       sst_mem_block_register(sst, offset, size,
+                                              region[i].type, NULL, j, sst);
+                       offset += size;
+               }
+       }
+
+       return 0;
+}
+
+static void sst_byt_free(struct sst_dsp *sst)
+{
+       sst_mem_block_unregister_all(sst);
+       iounmap(sst->addr.lpe);
+       iounmap(sst->addr.pci_cfg);
+       iounmap(sst->addr.fw_ext);
+}
+
+struct sst_ops sst_byt_ops = {
+       .reset = sst_byt_reset,
+       .boot = sst_byt_boot,
+       .write = sst_shim32_write,
+       .read = sst_shim32_read,
+       .write64 = sst_shim32_write64,
+       .read64 = sst_shim32_read64,
+       .ram_read = sst_memcpy_fromio_32,
+       .ram_write = sst_memcpy_toio_32,
+       .irq_handler = sst_byt_irq,
+       .init = sst_byt_init,
+       .free = sst_byt_free,
+       .parse_fw = sst_byt_parse_fw_image,
+};
diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c
new file mode 100644 (file)
index 0000000..1efb33b
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ * Intel Baytrail SST IPC Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+
+#include "sst-baytrail-ipc.h"
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "../common/sst-ipc.h"
+
+/* IPC message timeout */
+#define IPC_TIMEOUT_MSECS      300
+#define IPC_BOOT_MSECS         200
+
+#define IPC_EMPTY_LIST_SIZE    8
+
+/* IPC header bits */
+#define IPC_HEADER_MSG_ID_MASK 0xff
+#define IPC_HEADER_MSG_ID(x)   ((x) & IPC_HEADER_MSG_ID_MASK)
+#define IPC_HEADER_STR_ID_SHIFT        8
+#define IPC_HEADER_STR_ID_MASK 0x1f
+#define IPC_HEADER_STR_ID(x)   (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT)
+#define IPC_HEADER_LARGE_SHIFT 13
+#define IPC_HEADER_LARGE(x)    (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT)
+#define IPC_HEADER_DATA_SHIFT  16
+#define IPC_HEADER_DATA_MASK   0x3fff
+#define IPC_HEADER_DATA(x)     (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT)
+
+/* mask for differentiating between notification and reply message */
+#define IPC_NOTIFICATION       (0x1 << 7)
+
+/* I2L Stream config/control msgs */
+#define IPC_IA_ALLOC_STREAM    0x20
+#define IPC_IA_FREE_STREAM     0x21
+#define IPC_IA_PAUSE_STREAM    0x24
+#define IPC_IA_RESUME_STREAM   0x25
+#define IPC_IA_DROP_STREAM     0x26
+#define IPC_IA_START_STREAM    0x30
+
+/* notification messages */
+#define IPC_IA_FW_INIT_CMPLT   0x81
+#define IPC_SST_PERIOD_ELAPSED 0x97
+
+/* IPC messages between host and ADSP */
+struct sst_byt_address_info {
+       u32 addr;
+       u32 size;
+} __packed;
+
+struct sst_byt_str_type {
+       u8 codec_type;
+       u8 str_type;
+       u8 operation;
+       u8 protected_str;
+       u8 time_slots;
+       u8 reserved;
+       u16 result;
+} __packed;
+
+struct sst_byt_pcm_params {
+       u8 num_chan;
+       u8 pcm_wd_sz;
+       u8 use_offload_path;
+       u8 reserved;
+       u32 sfreq;
+       u8 channel_map[8];
+} __packed;
+
+struct sst_byt_frames_info {
+       u16 num_entries;
+       u16 rsrvd;
+       u32 frag_size;
+       struct sst_byt_address_info ring_buf_info[8];
+} __packed;
+
+struct sst_byt_alloc_params {
+       struct sst_byt_str_type str_type;
+       struct sst_byt_pcm_params pcm_params;
+       struct sst_byt_frames_info frame_info;
+} __packed;
+
+struct sst_byt_alloc_response {
+       struct sst_byt_str_type str_type;
+       u8 reserved[88];
+} __packed;
+
+struct sst_byt_start_stream_params {
+       u32 byte_offset;
+} __packed;
+
+struct sst_byt_tstamp {
+       u64 ring_buffer_counter;
+       u64 hardware_counter;
+       u64 frames_decoded;
+       u64 bytes_decoded;
+       u64 bytes_copied;
+       u32 sampling_frequency;
+       u32 channel_peak[8];
+} __packed;
+
+struct sst_byt_fw_version {
+       u8 build;
+       u8 minor;
+       u8 major;
+       u8 type;
+} __packed;
+
+struct sst_byt_fw_build_info {
+       u8 date[16];
+       u8 time[16];
+} __packed;
+
+struct sst_byt_fw_init {
+       struct sst_byt_fw_version fw_version;
+       struct sst_byt_fw_build_info build_info;
+       u16 result;
+       u8 module_id;
+       u8 debug_info;
+} __packed;
+
+struct sst_byt_stream;
+struct sst_byt;
+
+/* stream infomation */
+struct sst_byt_stream {
+       struct list_head node;
+
+       /* configuration */
+       struct sst_byt_alloc_params request;
+       struct sst_byt_alloc_response reply;
+
+       /* runtime info */
+       struct sst_byt *byt;
+       int str_id;
+       bool commited;
+       bool running;
+
+       /* driver callback */
+       u32 (*notify_position)(struct sst_byt_stream *stream, void *data);
+       void *pdata;
+};
+
+/* SST Baytrail IPC data */
+struct sst_byt {
+       struct device *dev;
+       struct sst_dsp *dsp;
+
+       /* stream */
+       struct list_head stream_list;
+
+       /* boot */
+       wait_queue_head_t boot_wait;
+       bool boot_complete;
+       struct sst_fw *fw;
+
+       /* IPC messaging */
+       struct sst_generic_ipc ipc;
+};
+
+static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id)
+{
+       u64 header;
+
+       header = IPC_HEADER_MSG_ID(msg_id) |
+                IPC_HEADER_STR_ID(str_id) |
+                IPC_HEADER_LARGE(large) |
+                IPC_HEADER_DATA(data) |
+                SST_BYT_IPCX_BUSY;
+
+       return header;
+}
+
+static inline u16 sst_byt_header_msg_id(u64 header)
+{
+       return header & IPC_HEADER_MSG_ID_MASK;
+}
+
+static inline u8 sst_byt_header_str_id(u64 header)
+{
+       return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK;
+}
+
+static inline u16 sst_byt_header_data(u64 header)
+{
+       return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK;
+}
+
+static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt,
+                                                int stream_id)
+{
+       struct sst_byt_stream *stream;
+
+       list_for_each_entry(stream, &byt->stream_list, node) {
+               if (stream->str_id == stream_id)
+                       return stream;
+       }
+
+       return NULL;
+}
+
+static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg)
+{
+       struct sst_byt_stream *stream;
+       u64 header = msg->header;
+       u8 stream_id = sst_byt_header_str_id(header);
+       u8 stream_msg = sst_byt_header_msg_id(header);
+
+       stream = sst_byt_get_stream(byt, stream_id);
+       if (stream == NULL)
+               return;
+
+       switch (stream_msg) {
+       case IPC_IA_DROP_STREAM:
+       case IPC_IA_PAUSE_STREAM:
+       case IPC_IA_FREE_STREAM:
+               stream->running = false;
+               break;
+       case IPC_IA_START_STREAM:
+       case IPC_IA_RESUME_STREAM:
+               stream->running = true;
+               break;
+       }
+}
+
+static int sst_byt_process_reply(struct sst_byt *byt, u64 header)
+{
+       struct ipc_message *msg;
+
+       msg = sst_ipc_reply_find_msg(&byt->ipc, header);
+       if (msg == NULL)
+               return 1;
+
+       if (header & IPC_HEADER_LARGE(true)) {
+               msg->rx_size = sst_byt_header_data(header);
+               sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size);
+       }
+
+       /* update any stream states */
+       sst_byt_stream_update(byt, msg);
+
+       list_del(&msg->list);
+       /* wake up */
+       sst_ipc_tx_msg_reply_complete(&byt->ipc, msg);
+
+       return 1;
+}
+
+static void sst_byt_fw_ready(struct sst_byt *byt, u64 header)
+{
+       dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header);
+
+       byt->boot_complete = true;
+       wake_up(&byt->boot_wait);
+}
+
+static int sst_byt_process_notification(struct sst_byt *byt,
+                                       unsigned long *flags)
+{
+       struct sst_dsp *sst = byt->dsp;
+       struct sst_byt_stream *stream;
+       u64 header;
+       u8 msg_id, stream_id;
+       int handled = 1;
+
+       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       msg_id = sst_byt_header_msg_id(header);
+
+       switch (msg_id) {
+       case IPC_SST_PERIOD_ELAPSED:
+               stream_id = sst_byt_header_str_id(header);
+               stream = sst_byt_get_stream(byt, stream_id);
+               if (stream && stream->running && stream->notify_position) {
+                       spin_unlock_irqrestore(&sst->spinlock, *flags);
+                       stream->notify_position(stream, stream->pdata);
+                       spin_lock_irqsave(&sst->spinlock, *flags);
+               }
+               break;
+       case IPC_IA_FW_INIT_CMPLT:
+               sst_byt_fw_ready(byt, header);
+               break;
+       }
+
+       return handled;
+}
+
+static irqreturn_t sst_byt_irq_thread(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       struct sst_byt *byt = sst_dsp_get_thread_context(sst);
+       struct sst_generic_ipc *ipc = &byt->ipc;
+       u64 header;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+
+       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       if (header & SST_BYT_IPCD_BUSY) {
+               if (header & IPC_NOTIFICATION) {
+                       /* message from ADSP */
+                       sst_byt_process_notification(byt, &flags);
+               } else {
+                       /* reply from ADSP */
+                       sst_byt_process_reply(byt, header);
+               }
+               /*
+                * clear IPCD BUSY bit and set DONE bit. Tell DSP we have
+                * processed the message and can accept new. Clear data part
+                * of the header
+                */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD,
+                       SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
+                       IPC_HEADER_DATA(IPC_HEADER_DATA_MASK),
+                       SST_BYT_IPCD_DONE);
+               /* unmask message request interrupts */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
+                       SST_BYT_IMRX_REQUEST, 0);
+       }
+
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       /* continue to send any remaining messages... */
+       queue_kthread_work(&ipc->kworker, &ipc->kwork);
+
+       return IRQ_HANDLED;
+}
+
+/* stream API */
+struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
+       u32 (*notify_position)(struct sst_byt_stream *stream, void *data),
+       void *data)
+{
+       struct sst_byt_stream *stream;
+       struct sst_dsp *sst = byt->dsp;
+       unsigned long flags;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (stream == NULL)
+               return NULL;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       list_add(&stream->node, &byt->stream_list);
+       stream->notify_position = notify_position;
+       stream->pdata = data;
+       stream->byt = byt;
+       stream->str_id = id;
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return stream;
+}
+
+int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           int bits)
+{
+       stream->request.pcm_params.pcm_wd_sz = bits;
+       return 0;
+}
+
+int sst_byt_stream_set_channels(struct sst_byt *byt,
+                               struct sst_byt_stream *stream, u8 channels)
+{
+       stream->request.pcm_params.num_chan = channels;
+       return 0;
+}
+
+int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           unsigned int rate)
+{
+       stream->request.pcm_params.sfreq = rate;
+       return 0;
+}
+
+/* stream sonfiguration */
+int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
+                       int codec_type, int stream_type, int operation)
+{
+       stream->request.str_type.codec_type = codec_type;
+       stream->request.str_type.str_type = stream_type;
+       stream->request.str_type.operation = operation;
+       stream->request.str_type.time_slots = 0xc;
+
+       return 0;
+}
+
+int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
+                         uint32_t buffer_addr, uint32_t buffer_size)
+{
+       stream->request.frame_info.num_entries = 1;
+       stream->request.frame_info.ring_buf_info[0].addr = buffer_addr;
+       stream->request.frame_info.ring_buf_info[0].size = buffer_size;
+       /* calculate bytes per 4 ms fragment */
+       stream->request.frame_info.frag_size =
+               stream->request.pcm_params.sfreq *
+               stream->request.pcm_params.num_chan *
+               stream->request.pcm_params.pcm_wd_sz / 8 *
+               4 / 1000;
+       return 0;
+}
+
+int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       struct sst_byt_alloc_params *str_req = &stream->request;
+       struct sst_byt_alloc_response *reply = &stream->reply;
+       u64 header;
+       int ret;
+
+       header = sst_byt_header(IPC_IA_ALLOC_STREAM,
+                               sizeof(*str_req) + sizeof(u32),
+                               true, stream->str_id);
+       ret = sst_ipc_tx_message_wait(&byt->ipc, header, str_req,
+                                     sizeof(*str_req),
+                                     reply, sizeof(*reply));
+       if (ret < 0) {
+               dev_err(byt->dev, "ipc: error stream commit failed\n");
+               return ret;
+       }
+
+       stream->commited = true;
+
+       return 0;
+}
+
+int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       u64 header;
+       int ret = 0;
+       struct sst_dsp *sst = byt->dsp;
+       unsigned long flags;
+
+       if (!stream->commited)
+               goto out;
+
+       header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id);
+       ret = sst_ipc_tx_message_wait(&byt->ipc, header, NULL, 0, NULL, 0);
+       if (ret < 0) {
+               dev_err(byt->dev, "ipc: free stream %d failed\n",
+                       stream->str_id);
+               return -EAGAIN;
+       }
+
+       stream->commited = false;
+out:
+       spin_lock_irqsave(&sst->spinlock, flags);
+       list_del(&stream->node);
+       kfree(stream);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return ret;
+}
+
+static int sst_byt_stream_operations(struct sst_byt *byt, int type,
+                                    int stream_id, int wait)
+{
+       u64 header;
+
+       header = sst_byt_header(type, 0, false, stream_id);
+       if (wait)
+               return sst_ipc_tx_message_wait(&byt->ipc, header, NULL,
+                                               0, NULL, 0);
+       else
+               return sst_ipc_tx_message_nowait(&byt->ipc, header,
+                                               NULL, 0);
+}
+
+/* stream ALSA trigger operations */
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
+                        u32 start_offset)
+{
+       struct sst_byt_start_stream_params start_stream;
+       void *tx_msg;
+       size_t size;
+       u64 header;
+       int ret;
+
+       start_stream.byte_offset = start_offset;
+       header = sst_byt_header(IPC_IA_START_STREAM,
+                               sizeof(start_stream) + sizeof(u32),
+                               true, stream->str_id);
+       tx_msg = &start_stream;
+       size = sizeof(start_stream);
+
+       ret = sst_ipc_tx_message_nowait(&byt->ipc, header, tx_msg, size);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to start stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       /* don't stop streams that are not commited */
+       if (!stream->commited)
+               return 0;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to stop stream %d\n",
+                       stream->str_id);
+       return ret;
+}
+
+int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to pause stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to resume stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_get_dsp_position(struct sst_byt *byt,
+                            struct sst_byt_stream *stream, int buffer_size)
+{
+       struct sst_dsp *sst = byt->dsp;
+       struct sst_byt_tstamp fw_tstamp;
+       u8 str_id = stream->str_id;
+       u32 tstamp_offset;
+
+       tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp);
+       memcpy_fromio(&fw_tstamp,
+                     sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp));
+
+       return do_div(fw_tstamp.ring_buffer_counter, buffer_size);
+}
+
+struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt)
+{
+       return byt->dsp;
+}
+
+static struct sst_dsp_device byt_dev = {
+       .thread = sst_byt_irq_thread,
+       .ops = &sst_byt_ops,
+};
+
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+
+       dev_dbg(byt->dev, "dsp reset\n");
+       sst_dsp_reset(byt->dsp);
+       sst_ipc_drop_all(&byt->ipc);
+       dev_dbg(byt->dev, "dsp in reset\n");
+
+       dev_dbg(byt->dev, "free all blocks and unload fw\n");
+       sst_fw_unload(byt->fw);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
+
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+       int ret;
+
+       dev_dbg(byt->dev, "reload dsp fw\n");
+
+       sst_dsp_reset(byt->dsp);
+
+       ret = sst_fw_reload(byt->fw);
+       if (ret <  0) {
+               dev_err(dev, "error: failed to reload firmware\n");
+               return ret;
+       }
+
+       /* wait for DSP boot completion */
+       byt->boot_complete = false;
+       sst_dsp_boot(byt->dsp);
+       dev_dbg(byt->dev, "dsp booting...\n");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
+
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+       int err;
+
+       dev_dbg(byt->dev, "wait for dsp reboot\n");
+
+       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+                                msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (err == 0) {
+               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+               return -EIO;
+       }
+
+       dev_dbg(byt->dev, "dsp rebooted\n");
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
+
+static void byt_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
+{
+       if (msg->header & IPC_HEADER_LARGE(true))
+               sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
+
+       sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->header);
+}
+
+static void byt_shim_dbg(struct sst_generic_ipc *ipc, const char *text)
+{
+       struct sst_dsp *sst = ipc->dsp;
+       u64 isr, ipcd, imrx, ipcx;
+
+       ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX);
+       isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
+       ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX);
+
+       dev_err(ipc->dev,
+               "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n",
+               text, ipcx, isr, ipcd, imrx);
+}
+
+static void byt_tx_data_copy(struct ipc_message *msg, char *tx_data,
+       size_t tx_size)
+{
+       /* msg content = lower 32-bit of the header + data */
+       *(u32 *)msg->tx_data = (u32)(msg->header & (u32)-1);
+       memcpy(msg->tx_data + sizeof(u32), tx_data, tx_size);
+       msg->tx_size += sizeof(u32);
+}
+
+static u64 byt_reply_msg_match(u64 header, u64 *mask)
+{
+       /* match reply to message sent based on msg and stream IDs */
+       *mask = IPC_HEADER_MSG_ID_MASK |
+              IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT;
+       header &= *mask;
+
+       return header;
+}
+
+int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt;
+       struct sst_generic_ipc *ipc;
+       struct sst_fw *byt_sst_fw;
+       struct sst_byt_fw_init init;
+       int err;
+
+       dev_dbg(dev, "initialising Byt DSP IPC\n");
+
+       byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL);
+       if (byt == NULL)
+               return -ENOMEM;
+
+       ipc = &byt->ipc;
+       ipc->dev = dev;
+       ipc->ops.tx_msg = byt_tx_msg;
+       ipc->ops.shim_dbg = byt_shim_dbg;
+       ipc->ops.tx_data_copy = byt_tx_data_copy;
+       ipc->ops.reply_msg_match = byt_reply_msg_match;
+
+       err = sst_ipc_init(ipc);
+       if (err != 0)
+               goto ipc_init_err;
+
+       INIT_LIST_HEAD(&byt->stream_list);
+       init_waitqueue_head(&byt->boot_wait);
+       byt_dev.thread_context = byt;
+
+       /* init SST shim */
+       byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
+       if (byt->dsp == NULL) {
+               err = -ENODEV;
+               goto dsp_new_err;
+       }
+
+       ipc->dsp = byt->dsp;
+
+       /* keep the DSP in reset state for base FW loading */
+       sst_dsp_reset(byt->dsp);
+
+       byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt);
+       if (byt_sst_fw  == NULL) {
+               err = -ENODEV;
+               dev_err(dev, "error: failed to load firmware\n");
+               goto fw_err;
+       }
+
+       /* wait for DSP boot completion */
+       sst_dsp_boot(byt->dsp);
+       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+                                msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (err == 0) {
+               err = -EIO;
+               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+               goto boot_err;
+       }
+
+       /* show firmware information */
+       sst_dsp_inbox_read(byt->dsp, &init, sizeof(init));
+       dev_info(byt->dev, "FW version: %02x.%02x.%02x.%02x\n",
+                init.fw_version.major, init.fw_version.minor,
+                init.fw_version.build, init.fw_version.type);
+       dev_info(byt->dev, "Build type: %x\n", init.fw_version.type);
+       dev_info(byt->dev, "Build date: %s %s\n",
+                init.build_info.date, init.build_info.time);
+
+       pdata->dsp = byt;
+       byt->fw = byt_sst_fw;
+
+       return 0;
+
+boot_err:
+       sst_dsp_reset(byt->dsp);
+       sst_fw_free(byt_sst_fw);
+fw_err:
+       sst_dsp_free(byt->dsp);
+dsp_new_err:
+       sst_ipc_fini(ipc);
+ipc_init_err:
+       kfree(byt);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_init);
+
+void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+
+       sst_dsp_reset(byt->dsp);
+       sst_fw_free_all(byt->dsp);
+       sst_dsp_free(byt->dsp);
+       sst_ipc_fini(&byt->ipc);
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_free);
diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.h b/sound/soc/intel/baytrail/sst-baytrail-ipc.h
new file mode 100644 (file)
index 0000000..8faff6d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Intel Baytrail SST IPC Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __SST_BYT_IPC_H
+#define __SST_BYT_IPC_H
+
+#include <linux/types.h>
+
+struct sst_byt;
+struct sst_byt_stream;
+struct sst_pdata;
+extern struct sst_ops sst_byt_ops;
+
+
+#define SST_BYT_MAILBOX_OFFSET         0x144000
+#define SST_BYT_TIMESTAMP_OFFSET       (SST_BYT_MAILBOX_OFFSET + 0x800)
+
+/**
+ * Upfront defined maximum message size that is
+ * expected by the in/out communication pipes in FW.
+ */
+#define SST_BYT_IPC_MAX_PAYLOAD_SIZE   200
+
+/* stream API */
+struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
+       uint32_t (*get_write_position)(struct sst_byt_stream *stream,
+                                      void *data),
+       void *data);
+
+/* stream configuration */
+int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           int bits);
+int sst_byt_stream_set_channels(struct sst_byt *byt,
+                               struct sst_byt_stream *stream, u8 channels);
+int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           unsigned int rate);
+int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
+                       int codec_type, int stream_type, int operation);
+int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
+                         uint32_t buffer_addr, uint32_t buffer_size);
+int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
+
+/* stream ALSA trigger operations */
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
+                        u32 start_offset);
+int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
+
+int sst_byt_get_dsp_position(struct sst_byt *byt,
+                            struct sst_byt_stream *stream, int buffer_size);
+
+/* init */
+int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
+void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
+struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
+
+#endif
diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
new file mode 100644 (file)
index 0000000..79547be
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * Intel Baytrail SST PCM Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "sst-baytrail-ipc.h"
+#include "../common/sst-dsp-priv.h"
+#include "../common/sst-dsp.h"
+
+#define BYT_PCM_COUNT          2
+
+static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S24_LE,
+       .period_bytes_min       = 384,
+       .period_bytes_max       = 48000,
+       .periods_min            = 2,
+       .periods_max            = 250,
+       .buffer_bytes_max       = 96000,
+};
+
+/* private data for each PCM DSP stream */
+struct sst_byt_pcm_data {
+       struct sst_byt_stream *stream;
+       struct snd_pcm_substream *substream;
+       struct mutex mutex;
+
+       /* latest DSP DMA hw pointer */
+       u32 hw_ptr;
+
+       struct work_struct work;
+};
+
+/* private data for the driver */
+struct sst_byt_priv_data {
+       /* runtime DSP */
+       struct sst_byt *byt;
+
+       /* DAI data */
+       struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
+
+       /* flag indicating is stream context restore needed after suspend */
+       bool restore_stream;
+};
+
+/* this may get called several times by oss emulation */
+static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+       u32 rate, bits;
+       u8 channels;
+       int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+       dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
+
+       ret = sst_byt_stream_type(byt, pcm_data->stream,
+                                 1, 1, !playback);
+       if (ret < 0) {
+               dev_err(rtd->dev, "failed to set stream format %d\n", ret);
+               return ret;
+       }
+
+       rate = params_rate(params);
+       ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set rate %d\n", rate);
+               return ret;
+       }
+
+       bits = snd_pcm_format_width(params_format(params));
+       ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set formats %d\n",
+                       params_rate(params));
+               return ret;
+       }
+
+       channels = (u8)(params_channels(params) & 0xF);
+       ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set channels %d\n",
+                       params_rate(params));
+               return ret;
+       }
+
+       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+
+       ret = sst_byt_stream_buffer(byt, pcm_data->stream,
+                                   substream->dma_buffer.addr,
+                                   params_buffer_bytes(params));
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
+               return ret;
+       }
+
+       ret = sst_byt_stream_commit(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->dev, "PCM: hw_free\n");
+       snd_pcm_lib_free_pages(substream);
+
+       return 0;
+}
+
+static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+       int ret;
+
+       /* commit stream using existing stream params */
+       ret = sst_byt_stream_commit(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+               return ret;
+       }
+
+       sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
+
+       dev_dbg(rtd->dev, "stream context restored at offset %d\n",
+               pcm_data->hw_ptr);
+
+       return 0;
+}
+
+static void sst_byt_pcm_work(struct work_struct *work)
+{
+       struct sst_byt_pcm_data *pcm_data =
+               container_of(work, struct sst_byt_pcm_data, work);
+
+       if (snd_pcm_running(pcm_data->substream))
+               sst_byt_pcm_restore_stream_context(pcm_data->substream);
+}
+
+static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+
+       dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               pcm_data->hw_ptr = 0;
+               sst_byt_stream_start(byt, pcm_data->stream, 0);
+               break;
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (pdata->restore_stream == true)
+                       schedule_work(&pcm_data->work);
+               else
+                       sst_byt_stream_resume(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               sst_byt_stream_resume(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               sst_byt_stream_stop(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               pdata->restore_stream = false;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               sst_byt_stream_pause(byt, pcm_data->stream);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
+{
+       struct sst_byt_pcm_data *pcm_data = data;
+       struct snd_pcm_substream *substream = pcm_data->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt *byt = pdata->byt;
+       u32 pos, hw_pos;
+
+       hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
+                                         snd_pcm_lib_buffer_bytes(substream));
+       pcm_data->hw_ptr = hw_pos;
+       pos = frames_to_bytes(runtime,
+                             (runtime->control->appl_ptr %
+                              runtime->buffer_size));
+
+       dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
+
+       snd_pcm_period_elapsed(substream);
+       return pos;
+}
+
+static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+
+       dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
+
+       return bytes_to_frames(runtime, pcm_data->hw_ptr);
+}
+
+static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+
+       dev_dbg(rtd->dev, "PCM: open\n");
+
+       mutex_lock(&pcm_data->mutex);
+
+       pcm_data->substream = substream;
+
+       snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
+
+       pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
+                                             byt_notify_pointer, pcm_data);
+       if (pcm_data->stream == NULL) {
+               dev_err(rtd->dev, "failed to create stream\n");
+               mutex_unlock(&pcm_data->mutex);
+               return -EINVAL;
+       }
+
+       mutex_unlock(&pcm_data->mutex);
+       return 0;
+}
+
+static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+       struct sst_byt *byt = pdata->byt;
+       int ret;
+
+       dev_dbg(rtd->dev, "PCM: close\n");
+
+       cancel_work_sync(&pcm_data->work);
+       mutex_lock(&pcm_data->mutex);
+       ret = sst_byt_stream_free(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_dbg(rtd->dev, "Free stream fail\n");
+               goto out;
+       }
+       pcm_data->stream = NULL;
+
+out:
+       mutex_unlock(&pcm_data->mutex);
+       return ret;
+}
+
+static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
+                           struct vm_area_struct *vma)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->dev, "PCM: mmap\n");
+       return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static struct snd_pcm_ops sst_byt_pcm_ops = {
+       .open           = sst_byt_pcm_open,
+       .close          = sst_byt_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = sst_byt_pcm_hw_params,
+       .hw_free        = sst_byt_pcm_hw_free,
+       .trigger        = sst_byt_pcm_trigger,
+       .pointer        = sst_byt_pcm_pointer,
+       .mmap           = sst_byt_pcm_mmap,
+};
+
+static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       size_t size;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+       int ret = 0;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+           pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               size = sst_byt_pcm_hardware.buffer_bytes_max;
+               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                                           SNDRV_DMA_TYPE_DEV,
+                                                           pdata->dma_dev,
+                                                           size, size);
+               if (ret) {
+                       dev_err(rtd->dev, "dma buffer allocation failed %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static struct snd_soc_dai_driver byt_dais[] = {
+       {
+               .name  = "Baytrail PCM",
+               .playback = {
+                       .stream_name = "System Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S24_3LE |
+                                  SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                       .stream_name = "Analog Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+       },
+};
+
+static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
+{
+       struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
+       struct sst_byt_priv_data *priv_data;
+       int i;
+
+       if (!plat_data)
+               return -ENODEV;
+
+       priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
+                                GFP_KERNEL);
+       priv_data->byt = plat_data->dsp;
+       snd_soc_platform_set_drvdata(platform, priv_data);
+
+       for (i = 0; i < BYT_PCM_COUNT; i++) {
+               mutex_init(&priv_data->pcm[i].mutex);
+               INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
+       }
+
+       return 0;
+}
+
+static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
+{
+       return 0;
+}
+
+static struct snd_soc_platform_driver byt_soc_platform = {
+       .probe          = sst_byt_pcm_probe,
+       .remove         = sst_byt_pcm_remove,
+       .ops            = &sst_byt_pcm_ops,
+       .pcm_new        = sst_byt_pcm_new,
+};
+
+static const struct snd_soc_component_driver byt_dai_component = {
+       .name           = "byt-dai",
+};
+
+#ifdef CONFIG_PM
+static int sst_byt_pcm_dev_suspend_late(struct device *dev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(dev, "suspending late\n");
+
+       ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
+       if (ret < 0) {
+               dev_err(dev, "failed to suspend %d\n", ret);
+               return ret;
+       }
+
+       priv_data->restore_stream = true;
+
+       return ret;
+}
+
+static int sst_byt_pcm_dev_resume_early(struct device *dev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       int ret;
+
+       dev_dbg(dev, "resume early\n");
+
+       /* load fw and boot DSP */
+       ret = sst_byt_dsp_boot(dev, sst_pdata);
+       if (ret)
+               return ret;
+
+       /* wait for FW to finish booting */
+       return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
+}
+
+static const struct dev_pm_ops sst_byt_pm_ops = {
+       .suspend_late = sst_byt_pcm_dev_suspend_late,
+       .resume_early = sst_byt_pcm_dev_resume_early,
+};
+
+#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
+#else
+#define SST_BYT_PM_OPS NULL
+#endif
+
+static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+       int ret;
+
+       ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
+       if (ret < 0)
+               return -ENODEV;
+
+       ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
+       if (ret < 0)
+               goto err_plat;
+
+       ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
+                                        byt_dais, ARRAY_SIZE(byt_dais));
+       if (ret < 0)
+               goto err_comp;
+
+       return 0;
+
+err_comp:
+       snd_soc_unregister_platform(&pdev->dev);
+err_plat:
+       sst_byt_dsp_free(&pdev->dev, sst_pdata);
+       return ret;
+}
+
+static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+
+       snd_soc_unregister_platform(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
+       sst_byt_dsp_free(&pdev->dev, sst_pdata);
+
+       return 0;
+}
+
+static struct platform_driver sst_byt_pcm_driver = {
+       .driver = {
+               .name = "baytrail-pcm-audio",
+               .pm = SST_BYT_PM_OPS,
+       },
+
+       .probe = sst_byt_pcm_dev_probe,
+       .remove = sst_byt_pcm_dev_remove,
+};
+module_platform_driver(sst_byt_pcm_driver);
+
+MODULE_AUTHOR("Jarkko Nikula");
+MODULE_DESCRIPTION("Baytrail PCM");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:baytrail-pcm-audio");
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
new file mode 100644 (file)
index 0000000..f8237f0
--- /dev/null
@@ -0,0 +1,15 @@
+snd-soc-sst-haswell-objs := haswell.o
+snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
+snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
+snd-soc-sst-broadwell-objs := broadwell.o
+snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
+snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
+snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
+
+obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
+obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
+obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
+obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
+obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
+obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
+obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
new file mode 100644 (file)
index 0000000..8bafaf6
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Intel Broadwell Wildcatpoint SST Audio
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+
+#include "../common/sst-dsp.h"
+#include "../haswell/sst-haswell-ipc.h"
+
+#include "../../codecs/rt286.h"
+
+static struct snd_soc_jack broadwell_headset;
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin broadwell_headset_pins[] = {
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static const struct snd_kcontrol_new broadwell_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+};
+
+static const struct snd_soc_dapm_widget broadwell_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_MIC("DMIC1", NULL),
+       SND_SOC_DAPM_MIC("DMIC2", NULL),
+       SND_SOC_DAPM_LINE("Line Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
+
+       /* speaker */
+       {"Speaker", NULL, "SPOR"},
+       {"Speaker", NULL, "SPOL"},
+
+       /* HP jack connectors - unknown if we have jack deteck */
+       {"Headphone Jack", NULL, "HPO Pin"},
+
+       /* other jacks */
+       {"MIC1", NULL, "Mic Jack"},
+       {"LINE1", NULL, "Line Jack"},
+
+       /* digital mics */
+       {"DMIC1 Pin", NULL, "DMIC1"},
+       {"DMIC2 Pin", NULL, "DMIC2"},
+
+       /* CODEC BE connections */
+       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret = 0;
+       ret = snd_soc_card_jack_new(rtd->card, "Headset",
+               SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
+               broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
+       if (ret)
+               return ret;
+
+       rt286_mic_detect(codec, &broadwell_headset);
+       return 0;
+}
+
+
+static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /* The ADSP will covert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 16 bit */
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+       return 0;
+}
+
+static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
+               SND_SOC_CLOCK_IN);
+
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec sysclk configuration\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static struct snd_soc_ops broadwell_rt286_ops = {
+       .hw_params = broadwell_rt286_hw_params,
+};
+
+static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
+       struct sst_hsw *broadwell = pdata->dsp;
+       int ret;
+
+       /* Set ADSP SSP port settings */
+       ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
+               SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
+               SST_HSW_DEVICE_CLOCK_MASTER, 9);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: failed to set device config\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/* broadwell digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link broadwell_rt286_dais[] = {
+       /* Front End DAI links */
+       {
+               .name = "System PCM",
+               .stream_name = "System Playback/Capture",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .init = broadwell_rtd_init,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "Offload0",
+               .stream_name = "Offload0 Playback",
+               .cpu_dai_name = "Offload0 Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "Offload1",
+               .stream_name = "Offload1 Playback",
+               .cpu_dai_name = "Offload1 Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "Loopback PCM",
+               .stream_name = "Loopback",
+               .cpu_dai_name = "Loopback Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 0,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+       },
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "Codec",
+               .be_id = 0,
+               .cpu_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "snd-soc-dummy",
+               .no_pcm = 1,
+               .codec_name = "i2c-INT343A:00",
+               .codec_dai_name = "rt286-aif1",
+               .init = broadwell_rt286_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_suspend = 1,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = broadwell_ssp0_fixup,
+               .ops = &broadwell_rt286_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+};
+
+static int broadwell_suspend(struct snd_soc_card *card){
+       struct snd_soc_codec *codec;
+
+       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
+               if (!strcmp(codec->component.name, "i2c-INT343A:00")) {
+                       dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
+                       rt286_mic_detect(codec, NULL);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int broadwell_resume(struct snd_soc_card *card){
+       struct snd_soc_codec *codec;
+
+       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
+               if (!strcmp(codec->component.name, "i2c-INT343A:00")) {
+                       dev_dbg(codec->dev, "enabling jack detect for resume.\n");
+                       rt286_mic_detect(codec, &broadwell_headset);
+                       break;
+               }
+       }
+       return 0;
+}
+
+/* broadwell audio machine driver for WPT + RT286S */
+static struct snd_soc_card broadwell_rt286 = {
+       .name = "broadwell-rt286",
+       .owner = THIS_MODULE,
+       .dai_link = broadwell_rt286_dais,
+       .num_links = ARRAY_SIZE(broadwell_rt286_dais),
+       .controls = broadwell_controls,
+       .num_controls = ARRAY_SIZE(broadwell_controls),
+       .dapm_widgets = broadwell_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
+       .dapm_routes = broadwell_rt286_map,
+       .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map),
+       .fully_routed = true,
+       .suspend_pre = broadwell_suspend,
+       .resume_post = broadwell_resume,
+};
+
+static int broadwell_audio_probe(struct platform_device *pdev)
+{
+       broadwell_rt286.dev = &pdev->dev;
+
+       return snd_soc_register_card(&broadwell_rt286);
+}
+
+static int broadwell_audio_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_card(&broadwell_rt286);
+       return 0;
+}
+
+static struct platform_driver broadwell_audio = {
+       .probe = broadwell_audio_probe,
+       .remove = broadwell_audio_remove,
+       .driver = {
+               .name = "broadwell-audio",
+       },
+};
+
+module_platform_driver(broadwell_audio)
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:broadwell-audio");
diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c
new file mode 100644 (file)
index 0000000..7ab8cc9
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Intel Baytrail SST MAX98090 machine driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/max98090.h"
+
+struct byt_max98090_private {
+       struct snd_soc_jack jack;
+};
+
+static const struct snd_soc_dapm_widget byt_max98090_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_max98090_audio_map[] = {
+       {"IN34", NULL, "Headset Mic"},
+       {"Headset Mic", NULL, "MICBIAS"},
+       {"DMICL", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPL"},
+       {"Headphone", NULL, "HPR"},
+       {"Ext Spk", NULL, "SPKL"},
+       {"Ext Spk", NULL, "SPKR"},
+};
+
+static const struct snd_kcontrol_new byt_max98090_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       {
+               .pin    = "Headphone",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+       {
+               .name           = "hp-gpio",
+               .idx            = 0,
+               .report         = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
+               .debounce_time  = 200,
+       },
+       {
+               .name           = "mic-gpio",
+               .idx            = 1,
+               .invert         = 1,
+               .report         = SND_JACK_MICROPHONE,
+               .debounce_time  = 200,
+       },
+};
+
+static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       struct snd_soc_card *card = runtime->card;
+       struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_jack *jack = &drv->jack;
+
+       card->dapm.idle_bias_off = true;
+
+       ret = snd_soc_dai_set_sysclk(runtime->codec_dai,
+                                    M98090_REG_SYSTEM_CLOCK,
+                                    25000000, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(card->dev, "Can't set codec clock %d\n", ret);
+               return ret;
+       }
+
+       /* Enable jack detection */
+       ret = snd_soc_card_jack_new(runtime->card, "Headset",
+                                   SND_JACK_LINEOUT | SND_JACK_HEADSET, jack,
+                                   hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
+       if (ret)
+               return ret;
+
+       return snd_soc_jack_add_gpiods(card->dev->parent, jack,
+                                      ARRAY_SIZE(hs_jack_gpios),
+                                      hs_jack_gpios);
+}
+
+static struct snd_soc_dai_link byt_max98090_dais[] = {
+       {
+               .name = "Baytrail Audio",
+               .stream_name = "Audio",
+               .cpu_dai_name = "baytrail-pcm-audio",
+               .codec_dai_name = "HiFi",
+               .codec_name = "i2c-193C9890:00",
+               .platform_name = "baytrail-pcm-audio",
+               .init = byt_max98090_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+       },
+};
+
+static struct snd_soc_card byt_max98090_card = {
+       .name = "byt-max98090",
+       .dai_link = byt_max98090_dais,
+       .num_links = ARRAY_SIZE(byt_max98090_dais),
+       .dapm_widgets = byt_max98090_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(byt_max98090_widgets),
+       .dapm_routes = byt_max98090_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
+       .controls = byt_max98090_controls,
+       .num_controls = ARRAY_SIZE(byt_max98090_controls),
+       .fully_routed = true,
+};
+
+static int byt_max98090_probe(struct platform_device *pdev)
+{
+       int ret_val = 0;
+       struct byt_max98090_private *priv;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+       if (!priv) {
+               dev_err(&pdev->dev, "allocation failed\n");
+               return -ENOMEM;
+       }
+
+       byt_max98090_card.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&byt_max98090_card, priv);
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card);
+       if (ret_val) {
+               dev_err(&pdev->dev,
+                       "snd_soc_register_card failed %d\n", ret_val);
+               return ret_val;
+       }
+
+       return ret_val;
+}
+
+static int byt_max98090_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct byt_max98090_private *priv = snd_soc_card_get_drvdata(card);
+
+       snd_soc_jack_free_gpios(&priv->jack, ARRAY_SIZE(hs_jack_gpios),
+                               hs_jack_gpios);
+
+       return 0;
+}
+
+static struct platform_driver byt_max98090_driver = {
+       .probe = byt_max98090_probe,
+       .remove = byt_max98090_remove,
+       .driver = {
+               .name = "byt-max98090",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+module_platform_driver(byt_max98090_driver)
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
+MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:byt-max98090");
diff --git a/sound/soc/intel/boards/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c
new file mode 100644 (file)
index 0000000..ae89b9b
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Intel Baytrail SST RT5640 machine driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/rt5640.h"
+
+#include "../common/sst-dsp.h"
+
+static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
+       {"Headset Mic", NULL, "MICBIAS1"},
+       {"IN2P", NULL, "Headset Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Speaker", NULL, "SPOLP"},
+       {"Speaker", NULL, "SPOLN"},
+       {"Speaker", NULL, "SPORP"},
+       {"Speaker", NULL, "SPORN"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
+       {"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
+       {"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
+       {"Internal Mic", NULL, "MICBIAS1"},
+       {"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+       BYT_RT5640_DMIC1_MAP,
+       BYT_RT5640_DMIC2_MAP,
+       BYT_RT5640_IN1_MAP,
+};
+
+#define BYT_RT5640_MAP(quirk)  ((quirk) & 0xff)
+#define BYT_RT5640_DMIC_EN     BIT(16)
+
+static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
+                                       BYT_RT5640_DMIC_EN;
+
+static const struct snd_kcontrol_new byt_rt5640_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic"),
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
+                                    params_rate(params) * 256,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(codec_dai->dev, "can't set codec clock %d\n", ret);
+               return ret;
+       }
+       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
+                                 params_rate(params) * 64,
+                                 params_rate(params) * 256);
+       if (ret < 0) {
+               dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
+{
+       byt_rt5640_quirk = (unsigned long)id->driver_data;
+       return 1;
+}
+
+static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+       {
+               .callback = byt_rt5640_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+               },
+               .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+       },
+       {
+               .callback = byt_rt5640_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
+               },
+               .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
+                                                BYT_RT5640_DMIC_EN),
+       },
+       {}
+};
+
+static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       struct snd_soc_codec *codec = runtime->codec;
+       struct snd_soc_card *card = runtime->card;
+       const struct snd_soc_dapm_route *custom_map;
+       int num_routes;
+
+       card->dapm.idle_bias_off = true;
+
+       ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
+                                       ARRAY_SIZE(byt_rt5640_controls));
+       if (ret) {
+               dev_err(card->dev, "unable to add card controls\n");
+               return ret;
+       }
+
+       dmi_check_system(byt_rt5640_quirk_table);
+       switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
+       case BYT_RT5640_IN1_MAP:
+               custom_map = byt_rt5640_intmic_in1_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
+               break;
+       case BYT_RT5640_DMIC2_MAP:
+               custom_map = byt_rt5640_intmic_dmic2_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
+               break;
+       default:
+               custom_map = byt_rt5640_intmic_dmic1_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
+       }
+
+       ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+       if (ret)
+               return ret;
+
+       if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
+               ret = rt5640_dmic_enable(codec, 0, 0);
+               if (ret)
+                       return ret;
+       }
+
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+
+       return ret;
+}
+
+static struct snd_soc_ops byt_rt5640_ops = {
+       .hw_params = byt_rt5640_hw_params,
+};
+
+static struct snd_soc_dai_link byt_rt5640_dais[] = {
+       {
+               .name = "Baytrail Audio",
+               .stream_name = "Audio",
+               .cpu_dai_name = "baytrail-pcm-audio",
+               .codec_dai_name = "rt5640-aif1",
+               .codec_name = "i2c-10EC5640:00",
+               .platform_name = "baytrail-pcm-audio",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .init = byt_rt5640_init,
+               .ops = &byt_rt5640_ops,
+       },
+};
+
+static struct snd_soc_card byt_rt5640_card = {
+       .name = "byt-rt5640",
+       .dai_link = byt_rt5640_dais,
+       .num_links = ARRAY_SIZE(byt_rt5640_dais),
+       .dapm_widgets = byt_rt5640_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
+       .dapm_routes = byt_rt5640_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+       .fully_routed = true,
+};
+
+static int byt_rt5640_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &byt_rt5640_card;
+
+       card->dev = &pdev->dev;
+       return devm_snd_soc_register_card(&pdev->dev, card);
+}
+
+static struct platform_driver byt_rt5640_audio = {
+       .probe = byt_rt5640_probe,
+       .driver = {
+               .name = "byt-rt5640",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+module_platform_driver(byt_rt5640_audio)
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
+MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:byt-rt5640");
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
new file mode 100644 (file)
index 0000000..7f55d59
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *  byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform
+ *
+ *  Copyright (C) 2014 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/rt5640.h"
+#include "../atom/sst-atom-controls.h"
+
+static const struct snd_soc_dapm_widget byt_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_audio_map[] = {
+       {"IN2P", NULL, "Headset Mic"},
+       {"IN2N", NULL, "Headset Mic"},
+       {"Headset Mic", NULL, "MICBIAS1"},
+       {"IN1P", NULL, "MICBIAS1"},
+       {"LDO2", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Ext Spk", NULL, "SPOLP"},
+       {"Ext Spk", NULL, "SPOLN"},
+       {"Ext Spk", NULL, "SPORP"},
+       {"Ext Spk", NULL, "SPORN"},
+
+       {"AIF1 Playback", NULL, "ssp2 Tx"},
+       {"ssp2 Tx", NULL, "codec_out0"},
+       {"ssp2 Tx", NULL, "codec_out1"},
+       {"codec_in0", NULL, "ssp2 Rx"},
+       {"codec_in1", NULL, "ssp2 Rx"},
+       {"ssp2 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_kcontrol_new byt_mc_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       snd_soc_dai_set_bclk_ratio(codec_dai, 50);
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
+                                    params_rate(params) * 512,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec clock %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
+                                 params_rate(params) * 50,
+                                 params_rate(params) * 512);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_pcm_stream byt_dai_params = {
+       .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+                           struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP2 to 24-bit */
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+       return 0;
+}
+
+static unsigned int rates_48000[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+       .count = ARRAY_SIZE(rates_48000),
+       .list  = rates_48000,
+};
+
+static int byt_aif1_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE,
+                       &constraints_48000);
+}
+
+static struct snd_soc_ops byt_aif1_ops = {
+       .startup = byt_aif1_startup,
+};
+
+static struct snd_soc_ops byt_be_ssp2_ops = {
+       .hw_params = byt_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link byt_dailink[] = {
+       [MERR_DPCM_AUDIO] = {
+               .name = "Baytrail Audio Port",
+               .stream_name = "Baytrail Audio",
+               .cpu_dai_name = "media-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .ignore_suspend = 1,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &byt_aif1_ops,
+       },
+       [MERR_DPCM_COMPR] = {
+               .name = "Baytrail Compressed Port",
+               .stream_name = "Baytrail Compress",
+               .cpu_dai_name = "compress-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+       },
+               /* back ends */
+       {
+               .name = "SSP2-Codec",
+               .be_id = 1,
+               .cpu_dai_name = "ssp2-port",
+               .platform_name = "sst-mfld-platform",
+               .no_pcm = 1,
+               .codec_dai_name = "rt5640-aif1",
+               .codec_name = "i2c-10EC5640:00",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                                               | SND_SOC_DAIFMT_CBS_CFS,
+               .be_hw_params_fixup = byt_codec_fixup,
+               .ignore_suspend = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &byt_be_ssp2_ops,
+       },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_byt = {
+       .name = "baytrailcraudio",
+       .dai_link = byt_dailink,
+       .num_links = ARRAY_SIZE(byt_dailink),
+       .dapm_widgets = byt_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets),
+       .dapm_routes = byt_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(byt_audio_map),
+       .controls = byt_mc_controls,
+       .num_controls = ARRAY_SIZE(byt_mc_controls),
+};
+
+static int snd_byt_mc_probe(struct platform_device *pdev)
+{
+       int ret_val = 0;
+
+       /* register the soc card */
+       snd_soc_card_byt.dev = &pdev->dev;
+
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt);
+       if (ret_val) {
+               dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val);
+               return ret_val;
+       }
+       platform_set_drvdata(pdev, &snd_soc_card_byt);
+       return ret_val;
+}
+
+static struct platform_driver snd_byt_mc_driver = {
+       .driver = {
+               .name = "bytt100_rt5640",
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = snd_byt_mc_probe,
+};
+
+module_platform_driver(snd_byt_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
+MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytt100_rt5640");
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
new file mode 100644 (file)
index 0000000..20a28b2
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ *  cht-bsw-rt5645.c - ASoc Machine driver for Intel Cherryview-based platforms
+ *                     Cherrytrail and Braswell, with RT5645 codec.
+ *
+ *  Copyright (C) 2015 Intel Corp
+ *  Author: Fang, Yang A <yang.a.fang@intel.com>
+ *             N,Harshapriya <harshapriya.n@intel.com>
+ *  This file is modified from cht_bsw_rt5672.c
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/rt5645.h"
+#include "../atom/sst-atom-controls.h"
+
+#define CHT_PLAT_CLK_3_HZ      19200000
+#define CHT_CODEC_DAI  "rt5645-aif1"
+
+struct cht_mc_private {
+       struct snd_soc_jack hp_jack;
+       struct snd_soc_jack mic_jack;
+};
+
+static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
+{
+       int i;
+
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_pcm_runtime *rtd;
+
+               rtd = card->rtd + i;
+               if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
+                            strlen(CHT_CODEC_DAI)))
+                       return rtd->codec_dai;
+       }
+       return NULL;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *k, int  event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dai *codec_dai;
+       int ret;
+
+       codec_dai = cht_get_codec_dai(card);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
+               return -EIO;
+       }
+
+       if (!SND_SOC_DAPM_EVENT_OFF(event))
+               return 0;
+
+       /* Set codec sysclk source to its internal clock because codec PLL will
+        * be off when idle and MCLK will also be off by ACPI when codec is
+        * runtime suspended. Codec needs clock for jack detection and button
+        * press.
+        */
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
+                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+                       platform_clock_control, SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route cht_audio_map[] = {
+       {"IN1P", NULL, "Headset Mic"},
+       {"IN1N", NULL, "Headset Mic"},
+       {"DMIC L1", NULL, "Int Mic"},
+       {"DMIC R1", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Ext Spk", NULL, "SPOL"},
+       {"Ext Spk", NULL, "SPOR"},
+       {"AIF1 Playback", NULL, "ssp2 Tx"},
+       {"ssp2 Tx", NULL, "codec_out0"},
+       {"ssp2 Tx", NULL, "codec_out1"},
+       {"codec_in0", NULL, "ssp2 Rx" },
+       {"codec_in1", NULL, "ssp2 Rx" },
+       {"ssp2 Rx", NULL, "AIF1 Capture"},
+       {"Headphone", NULL, "Platform Clock"},
+       {"Headset Mic", NULL, "Platform Clock"},
+       {"Int Mic", NULL, "Platform Clock"},
+       {"Ext Spk", NULL, "Platform Clock"},
+};
+
+static const struct snd_kcontrol_new cht_mc_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
+       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
+                                 CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1,
+                               params_rate(params) * 512, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       struct snd_soc_codec *codec = runtime->codec;
+       struct snd_soc_dai *codec_dai = runtime->codec_dai;
+       struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
+
+       /* Select clk_i2s1_asrc as ASRC clock source */
+       rt5645_sel_asrc_clk_src(codec,
+                               RT5645_DA_STEREO_FILTER |
+                               RT5645_DA_MONO_L_FILTER |
+                               RT5645_DA_MONO_R_FILTER |
+                               RT5645_AD_STEREO_FILTER,
+                               RT5645_CLK_SEL_I2S1_ASRC);
+
+       /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+       if (ret < 0) {
+               dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack",
+                                   SND_JACK_HEADPHONE, &ctx->hp_jack,
+                                   NULL, 0);
+       if (ret) {
+               dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_card_jack_new(runtime->card, "Mic Jack",
+                                   SND_JACK_MICROPHONE, &ctx->mic_jack,
+                                   NULL, 0);
+       if (ret) {
+               dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack);
+
+       return ret;
+}
+
+static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+                           struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP2 to 24-bit */
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+       return 0;
+}
+
+static unsigned int rates_48000[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+       .count = ARRAY_SIZE(rates_48000),
+       .list  = rates_48000,
+};
+
+static int cht_aif1_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE,
+                       &constraints_48000);
+}
+
+static struct snd_soc_ops cht_aif1_ops = {
+       .startup = cht_aif1_startup,
+};
+
+static struct snd_soc_ops cht_be_ssp2_ops = {
+       .hw_params = cht_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link cht_dailink[] = {
+       [MERR_DPCM_AUDIO] = {
+               .name = "Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "media-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .ignore_suspend = 1,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &cht_aif1_ops,
+       },
+       [MERR_DPCM_COMPR] = {
+               .name = "Compressed Port",
+               .stream_name = "Compress",
+               .cpu_dai_name = "compress-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+       },
+       /* CODEC<->CODEC link */
+       /* back ends */
+       {
+               .name = "SSP2-Codec",
+               .be_id = 1,
+               .cpu_dai_name = "ssp2-port",
+               .platform_name = "sst-mfld-platform",
+               .no_pcm = 1,
+               .codec_dai_name = "rt5645-aif1",
+               .codec_name = "i2c-10EC5645:00",
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
+                                       | SND_SOC_DAIFMT_CBS_CFS,
+               .init = cht_codec_init,
+               .be_hw_params_fixup = cht_codec_fixup,
+               .ignore_suspend = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &cht_be_ssp2_ops,
+       },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_cht = {
+       .name = "chtrt5645",
+       .dai_link = cht_dailink,
+       .num_links = ARRAY_SIZE(cht_dailink),
+       .dapm_widgets = cht_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
+       .dapm_routes = cht_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
+       .controls = cht_mc_controls,
+       .num_controls = ARRAY_SIZE(cht_mc_controls),
+};
+
+static int snd_cht_mc_probe(struct platform_device *pdev)
+{
+       int ret_val = 0;
+       struct cht_mc_private *drv;
+
+       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+       if (!drv)
+               return -ENOMEM;
+
+       snd_soc_card_cht.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
+       if (ret_val) {
+               dev_err(&pdev->dev,
+                       "snd_soc_register_card failed %d\n", ret_val);
+               return ret_val;
+       }
+       platform_set_drvdata(pdev, &snd_soc_card_cht);
+       return ret_val;
+}
+
+static struct platform_driver snd_cht_mc_driver = {
+       .driver = {
+               .name = "cht-bsw-rt5645",
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = snd_cht_mc_probe,
+};
+
+module_platform_driver(snd_cht_mc_driver)
+
+MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
+MODULE_AUTHOR("Fang, Yang A,N,Harshapriya");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cht-bsw-rt5645");
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
new file mode 100644 (file)
index 0000000..2c9cc5b
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ *  cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms
+ *                     Cherrytrail and Braswell, with RT5672 codec.
+ *
+ *  Copyright (C) 2014 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *          Mengdong Lin <mengdong.lin@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/rt5670.h"
+#include "../atom/sst-atom-controls.h"
+
+/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */
+#define CHT_PLAT_CLK_3_HZ      19200000
+#define CHT_CODEC_DAI  "rt5670-aif1"
+
+static struct snd_soc_jack cht_bsw_headset;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
+{
+       int i;
+
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_pcm_runtime *rtd;
+
+               rtd = card->rtd + i;
+               if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
+                            strlen(CHT_CODEC_DAI)))
+                       return rtd->codec_dai;
+       }
+       return NULL;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *k, int  event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dai *codec_dai;
+       int ret;
+
+       codec_dai = cht_get_codec_dai(card);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
+               return -EIO;
+       }
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
+               ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
+                               CHT_PLAT_CLK_3_HZ, 48000 * 512);
+               if (ret < 0) {
+                       dev_err(card->dev, "can't set codec pll: %d\n", ret);
+                       return ret;
+               }
+
+               /* set codec sysclk source to PLL */
+               ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
+                       48000 * 512, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
+                       return ret;
+               }
+       } else {
+               /* Set codec sysclk source to its internal clock because codec
+                * PLL will be off when idle and MCLK will also be off by ACPI
+                * when codec is runtime suspended. Codec needs clock for jack
+                * detection and button press.
+                */
+               snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
+                                      48000 * 512, SND_SOC_CLOCK_IN);
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+                       platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route cht_audio_map[] = {
+       {"IN1P", NULL, "Headset Mic"},
+       {"IN1N", NULL, "Headset Mic"},
+       {"DMIC L1", NULL, "Int Mic"},
+       {"DMIC R1", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Ext Spk", NULL, "SPOLP"},
+       {"Ext Spk", NULL, "SPOLN"},
+       {"Ext Spk", NULL, "SPORP"},
+       {"Ext Spk", NULL, "SPORN"},
+       {"AIF1 Playback", NULL, "ssp2 Tx"},
+       {"ssp2 Tx", NULL, "codec_out0"},
+       {"ssp2 Tx", NULL, "codec_out1"},
+       {"codec_in0", NULL, "ssp2 Rx"},
+       {"codec_in1", NULL, "ssp2 Rx"},
+       {"ssp2 Rx", NULL, "AIF1 Capture"},
+       {"Headphone", NULL, "Platform Clock"},
+       {"Headset Mic", NULL, "Platform Clock"},
+       {"Int Mic", NULL, "Platform Clock"},
+       {"Ext Spk", NULL, "Platform Clock"},
+};
+
+static const struct snd_kcontrol_new cht_mc_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
+       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
+                                 CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+               return ret;
+       }
+
+       /* set codec sysclk source to PLL */
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
+                                    params_rate(params) * 512,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       struct snd_soc_dai *codec_dai = runtime->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+       if (ret < 0) {
+               dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
+               return ret;
+       }
+
+       /* Select codec ASRC clock source to track I2S1 clock, because codec
+        * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
+        * be supported by RT5672. Otherwise, ASRC will be disabled and cause
+        * noise.
+        */
+       rt5670_sel_asrc_clk_src(codec,
+                               RT5670_DA_STEREO_FILTER
+                               | RT5670_DA_MONO_L_FILTER
+                               | RT5670_DA_MONO_R_FILTER
+                               | RT5670_AD_STEREO_FILTER
+                               | RT5670_AD_MONO_L_FILTER
+                               | RT5670_AD_MONO_R_FILTER,
+                               RT5670_CLK_SEL_I2S1_ASRC);
+
+        ret = snd_soc_card_jack_new(runtime->card, "Headset",
+                SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset,
+                cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins));
+        if (ret)
+                return ret;
+
+       rt5670_set_jack_detect(codec, &cht_bsw_headset);
+       return 0;
+}
+
+static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+                           struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP2 to 24-bit */
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+       return 0;
+}
+
+static unsigned int rates_48000[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+       .count = ARRAY_SIZE(rates_48000),
+       .list  = rates_48000,
+};
+
+static int cht_aif1_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE,
+                       &constraints_48000);
+}
+
+static struct snd_soc_ops cht_aif1_ops = {
+       .startup = cht_aif1_startup,
+};
+
+static struct snd_soc_ops cht_be_ssp2_ops = {
+       .hw_params = cht_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link cht_dailink[] = {
+       /* Front End DAI links */
+       [MERR_DPCM_AUDIO] = {
+               .name = "Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "media-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &cht_aif1_ops,
+       },
+       [MERR_DPCM_COMPR] = {
+               .name = "Compressed Port",
+               .stream_name = "Compress",
+               .cpu_dai_name = "compress-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP2 - Codec */
+               .name = "SSP2-Codec",
+               .be_id = 1,
+               .cpu_dai_name = "ssp2-port",
+               .platform_name = "sst-mfld-platform",
+               .no_pcm = 1,
+               .nonatomic = true,
+               .codec_dai_name = "rt5670-aif1",
+               .codec_name = "i2c-10EC5670:00",
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
+                                       | SND_SOC_DAIFMT_CBS_CFS,
+               .init = cht_codec_init,
+               .be_hw_params_fixup = cht_codec_fixup,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &cht_be_ssp2_ops,
+       },
+};
+
+static int cht_suspend_pre(struct snd_soc_card *card)
+{
+       struct snd_soc_codec *codec;
+
+       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
+               if (!strcmp(codec->component.name, "i2c-10EC5670:00")) {
+                       dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
+                       rt5670_jack_suspend(codec);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int cht_resume_post(struct snd_soc_card *card)
+{
+       struct snd_soc_codec *codec;
+
+       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
+               if (!strcmp(codec->component.name, "i2c-10EC5670:00")) {
+                       dev_dbg(codec->dev, "enabling jack detect for resume.\n");
+                       rt5670_jack_resume(codec);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_cht = {
+       .name = "cherrytrailcraudio",
+       .dai_link = cht_dailink,
+       .num_links = ARRAY_SIZE(cht_dailink),
+       .dapm_widgets = cht_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
+       .dapm_routes = cht_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
+       .controls = cht_mc_controls,
+       .num_controls = ARRAY_SIZE(cht_mc_controls),
+       .suspend_pre = cht_suspend_pre,
+       .resume_post = cht_resume_post,
+};
+
+static int snd_cht_mc_probe(struct platform_device *pdev)
+{
+       int ret_val = 0;
+
+       /* register the soc card */
+       snd_soc_card_cht.dev = &pdev->dev;
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
+       if (ret_val) {
+               dev_err(&pdev->dev,
+                       "snd_soc_register_card failed %d\n", ret_val);
+               return ret_val;
+       }
+       platform_set_drvdata(pdev, &snd_soc_card_cht);
+       return ret_val;
+}
+
+static struct platform_driver snd_cht_mc_driver = {
+       .driver = {
+               .name = "cht-bsw-rt5672",
+       },
+       .probe = snd_cht_mc_probe,
+};
+
+module_platform_driver(snd_cht_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
+MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cht-bsw-rt5672");
diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
new file mode 100644 (file)
index 0000000..2255857
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Intel Haswell Lynxpoint SST Audio
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "../common/sst-dsp.h"
+#include "../haswell/sst-haswell-ipc.h"
+
+#include "../../codecs/rt5640.h"
+
+/* Haswell ULT platforms have a Headphone and Mic jack */
+static const struct snd_soc_dapm_widget haswell_widgets[] = {
+       SND_SOC_DAPM_HP("Headphones", NULL),
+       SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
+
+       {"Headphones", NULL, "HPOR"},
+       {"Headphones", NULL, "HPOL"},
+       {"IN2P", NULL, "Mic"},
+
+       /* CODEC BE connections */
+       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /* The ADSP will covert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 16 bit */
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+       return 0;
+}
+
+static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
+               SND_SOC_CLOCK_IN);
+
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec sysclk configuration\n");
+               return ret;
+       }
+
+       /* set correct codec filter for DAI format and clock config */
+       snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
+
+       return ret;
+}
+
+static struct snd_soc_ops haswell_rt5640_ops = {
+       .hw_params = haswell_rt5640_hw_params,
+};
+
+static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
+       struct sst_hsw *haswell = pdata->dsp;
+       int ret;
+
+       /* Set ADSP SSP port settings */
+       ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
+               SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
+               SST_HSW_DEVICE_CLOCK_MASTER, 9);
+       if (ret < 0) {
+               dev_err(rtd->dev, "failed to set device config\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_dai_link haswell_rt5640_dais[] = {
+       /* Front End DAI links */
+       {
+               .name = "System",
+               .stream_name = "System Playback/Capture",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .init = haswell_rtd_init,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "Offload0",
+               .stream_name = "Offload0 Playback",
+               .cpu_dai_name = "Offload0 Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "Offload1",
+               .stream_name = "Offload1 Playback",
+               .cpu_dai_name = "Offload1 Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "Loopback",
+               .stream_name = "Loopback",
+               .cpu_dai_name = "Loopback Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 0,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "Codec",
+               .be_id = 0,
+               .cpu_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "snd-soc-dummy",
+               .no_pcm = 1,
+               .codec_name = "i2c-INT33CA:00",
+               .codec_dai_name = "rt5640-aif1",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_suspend = 1,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = haswell_ssp0_fixup,
+               .ops = &haswell_rt5640_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+};
+
+/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
+static struct snd_soc_card haswell_rt5640 = {
+       .name = "haswell-rt5640",
+       .owner = THIS_MODULE,
+       .dai_link = haswell_rt5640_dais,
+       .num_links = ARRAY_SIZE(haswell_rt5640_dais),
+       .dapm_widgets = haswell_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
+       .dapm_routes = haswell_rt5640_map,
+       .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
+       .fully_routed = true,
+};
+
+static int haswell_audio_probe(struct platform_device *pdev)
+{
+       haswell_rt5640.dev = &pdev->dev;
+
+       return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640);
+}
+
+static struct platform_driver haswell_audio = {
+       .probe = haswell_audio_probe,
+       .driver = {
+               .name = "haswell-audio",
+       },
+};
+
+module_platform_driver(haswell_audio)
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:haswell-audio");
diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c
new file mode 100644 (file)
index 0000000..49c09a0
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ *  mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform
+ *
+ *  Copyright (C) 2010 Intel Corp
+ *  Author: Vinod Koul <vinod.koul@intel.com>
+ *  Author: Harsha Priya <priya.harsha@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/sn95031.h"
+
+#define MID_MONO 1
+#define MID_STEREO 2
+#define MID_MAX_CAP 5
+#define MFLD_JACK_INSERT 0x04
+
+enum soc_mic_bias_zones {
+       MFLD_MV_START = 0,
+       /* mic bias volutage range for Headphones*/
+       MFLD_MV_HP = 400,
+       /* mic bias volutage range for American Headset*/
+       MFLD_MV_AM_HS = 650,
+       /* mic bias volutage range for Headset*/
+       MFLD_MV_HS = 2000,
+       MFLD_MV_UNDEFINED,
+};
+
+static unsigned int    hs_switch;
+static unsigned int    lo_dac;
+static struct snd_soc_codec *mfld_codec;
+
+struct mfld_mc_private {
+       void __iomem *int_base;
+       u8 interrupt_status;
+};
+
+struct snd_soc_jack mfld_jack;
+
+/*Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin mfld_jack_pins[] = {
+       {
+               .pin = "Headphones",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "AMIC1",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+/* jack detection voltage zones */
+static struct snd_soc_jack_zone mfld_zones[] = {
+       {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
+       {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET},
+};
+
+/* sound card controls */
+static const char *headset_switch_text[] = {"Earpiece", "Headset"};
+
+static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"};
+
+static const struct soc_enum headset_enum =
+       SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
+
+static const struct soc_enum lo_enum =
+       SOC_ENUM_SINGLE_EXT(4, lo_text);
+
+static int headset_get_switch(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = hs_switch;
+       return 0;
+}
+
+static int headset_set_switch(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_context *dapm = &card->dapm;
+
+       if (ucontrol->value.integer.value[0] == hs_switch)
+               return 0;
+
+       snd_soc_dapm_mutex_lock(dapm);
+
+       if (ucontrol->value.integer.value[0]) {
+               pr_debug("hs_set HS path\n");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
+       } else {
+               pr_debug("hs_set EP path\n");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
+       }
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
+
+       hs_switch = ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
+static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
+{
+       snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
+       if (hs_switch) {
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
+       } else {
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
+       }
+}
+
+static int lo_get_switch(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = lo_dac;
+       return 0;
+}
+
+static int lo_set_switch(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_context *dapm = &card->dapm;
+
+       if (ucontrol->value.integer.value[0] == lo_dac)
+               return 0;
+
+       snd_soc_dapm_mutex_lock(dapm);
+
+       /* we dont want to work with last state of lineout so just enable all
+        * pins and then disable pins not required
+        */
+       lo_enable_out_pins(dapm);
+
+       switch (ucontrol->value.integer.value[0]) {
+       case 0:
+               pr_debug("set vibra path\n");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
+               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
+               break;
+
+       case 1:
+               pr_debug("set hs  path\n");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
+               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
+               break;
+
+       case 2:
+               pr_debug("set spkr path\n");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
+               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
+               break;
+
+       case 3:
+               pr_debug("set null path\n");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
+               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
+               break;
+       }
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
+
+       lo_dac = ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static const struct snd_kcontrol_new mfld_snd_controls[] = {
+       SOC_ENUM_EXT("Playback Switch", headset_enum,
+                       headset_get_switch, headset_set_switch),
+       SOC_ENUM_EXT("Lineout Mux", lo_enum,
+                       lo_get_switch, lo_set_switch),
+};
+
+static const struct snd_soc_dapm_widget mfld_widgets[] = {
+       SND_SOC_DAPM_HP("Headphones", NULL),
+       SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mfld_map[] = {
+       {"Headphones", NULL, "HPOUTR"},
+       {"Headphones", NULL, "HPOUTL"},
+       {"Mic", NULL, "AMIC1"},
+};
+
+static void mfld_jack_check(unsigned int intr_status)
+{
+       struct mfld_jack_data jack_data;
+
+       if (!mfld_codec)
+               return;
+
+       jack_data.mfld_jack = &mfld_jack;
+       jack_data.intr_id = intr_status;
+
+       sn95031_jack_detection(mfld_codec, &jack_data);
+       /* TODO: add american headset detection post gpiolib support */
+}
+
+static int mfld_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
+       int ret_val;
+
+       /* default is earpiece pin, userspace sets it explcitly */
+       snd_soc_dapm_disable_pin(dapm, "Headphones");
+       /* default is lineout NC, userspace sets it explcitly */
+       snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
+       snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
+       lo_dac = 3;
+       hs_switch = 0;
+       /* we dont use linein in this so set to NC */
+       snd_soc_dapm_disable_pin(dapm, "LINEINL");
+       snd_soc_dapm_disable_pin(dapm, "LINEINR");
+
+       /* Headset and button jack detection */
+       ret_val = snd_soc_card_jack_new(runtime->card,
+                       "Intel(R) MID Audio Jack", SND_JACK_HEADSET |
+                       SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack,
+                       mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins));
+       if (ret_val) {
+               pr_err("jack creation failed\n");
+               return ret_val;
+       }
+
+       ret_val = snd_soc_jack_add_zones(&mfld_jack,
+                       ARRAY_SIZE(mfld_zones), mfld_zones);
+       if (ret_val) {
+               pr_err("adding jack zones failed\n");
+               return ret_val;
+       }
+
+       mfld_codec = runtime->codec;
+
+       /* we want to check if anything is inserted at boot,
+        * so send a fake event to codec and it will read adc
+        * to find if anything is there or not */
+       mfld_jack_check(MFLD_JACK_INSERT);
+       return ret_val;
+}
+
+static struct snd_soc_dai_link mfld_msic_dailink[] = {
+       {
+               .name = "Medfield Headset",
+               .stream_name = "Headset",
+               .cpu_dai_name = "Headset-cpu-dai",
+               .codec_dai_name = "SN95031 Headset",
+               .codec_name = "sn95031",
+               .platform_name = "sst-platform",
+               .init = mfld_init,
+       },
+       {
+               .name = "Medfield Speaker",
+               .stream_name = "Speaker",
+               .cpu_dai_name = "Speaker-cpu-dai",
+               .codec_dai_name = "SN95031 Speaker",
+               .codec_name = "sn95031",
+               .platform_name = "sst-platform",
+               .init = NULL,
+       },
+       {
+               .name = "Medfield Vibra",
+               .stream_name = "Vibra1",
+               .cpu_dai_name = "Vibra1-cpu-dai",
+               .codec_dai_name = "SN95031 Vibra1",
+               .codec_name = "sn95031",
+               .platform_name = "sst-platform",
+               .init = NULL,
+       },
+       {
+               .name = "Medfield Haptics",
+               .stream_name = "Vibra2",
+               .cpu_dai_name = "Vibra2-cpu-dai",
+               .codec_dai_name = "SN95031 Vibra2",
+               .codec_name = "sn95031",
+               .platform_name = "sst-platform",
+               .init = NULL,
+       },
+       {
+               .name = "Medfield Compress",
+               .stream_name = "Speaker",
+               .cpu_dai_name = "Compress-cpu-dai",
+               .codec_dai_name = "SN95031 Speaker",
+               .codec_name = "sn95031",
+               .platform_name = "sst-platform",
+               .init = NULL,
+       },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_mfld = {
+       .name = "medfield_audio",
+       .owner = THIS_MODULE,
+       .dai_link = mfld_msic_dailink,
+       .num_links = ARRAY_SIZE(mfld_msic_dailink),
+
+       .controls = mfld_snd_controls,
+       .num_controls = ARRAY_SIZE(mfld_snd_controls),
+       .dapm_widgets = mfld_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
+       .dapm_routes = mfld_map,
+       .num_dapm_routes = ARRAY_SIZE(mfld_map),
+};
+
+static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
+{
+       struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev;
+
+       memcpy_fromio(&mc_private->interrupt_status,
+                       ((void *)(mc_private->int_base)),
+                       sizeof(u8));
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
+{
+       struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
+
+       mfld_jack_check(mc_drv_ctx->interrupt_status);
+
+       return IRQ_HANDLED;
+}
+
+static int snd_mfld_mc_probe(struct platform_device *pdev)
+{
+       int ret_val = 0, irq;
+       struct mfld_mc_private *mc_drv_ctx;
+       struct resource *irq_mem;
+
+       pr_debug("snd_mfld_mc_probe called\n");
+
+       /* retrive the irq number */
+       irq = platform_get_irq(pdev, 0);
+
+       /* audio interrupt base of SRAM location where
+        * interrupts are stored by System FW */
+       mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
+       if (!mc_drv_ctx) {
+               pr_err("allocation failed\n");
+               return -ENOMEM;
+       }
+
+       irq_mem = platform_get_resource_byname(
+                               pdev, IORESOURCE_MEM, "IRQ_BASE");
+       if (!irq_mem) {
+               pr_err("no mem resource given\n");
+               return -ENODEV;
+       }
+       mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start,
+                                                   resource_size(irq_mem));
+       if (!mc_drv_ctx->int_base) {
+               pr_err("Mapping of cache failed\n");
+               return -ENOMEM;
+       }
+       /* register for interrupt */
+       ret_val = devm_request_threaded_irq(&pdev->dev, irq,
+                       snd_mfld_jack_intr_handler,
+                       snd_mfld_jack_detection,
+                       IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
+       if (ret_val) {
+               pr_err("cannot register IRQ\n");
+               return ret_val;
+       }
+       /* register the soc card */
+       snd_soc_card_mfld.dev = &pdev->dev;
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld);
+       if (ret_val) {
+               pr_debug("snd_soc_register_card failed %d\n", ret_val);
+               return ret_val;
+       }
+       platform_set_drvdata(pdev, mc_drv_ctx);
+       pr_debug("successfully exited probe\n");
+       return 0;
+}
+
+static struct platform_driver snd_mfld_mc_driver = {
+       .driver = {
+               .name = "msic_audio",
+       },
+       .probe = snd_mfld_mc_probe,
+};
+
+module_platform_driver(snd_mfld_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:msic-audio");
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c
deleted file mode 100644 (file)
index 9cf7d01..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Intel Broadwell Wildcatpoint SST Audio
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include <sound/pcm_params.h>
-
-#include "sst-dsp.h"
-#include "sst-haswell-ipc.h"
-
-#include "../codecs/rt286.h"
-
-static struct snd_soc_jack broadwell_headset;
-/* Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin broadwell_headset_pins[] = {
-       {
-               .pin = "Mic Jack",
-               .mask = SND_JACK_MICROPHONE,
-       },
-       {
-               .pin = "Headphone Jack",
-               .mask = SND_JACK_HEADPHONE,
-       },
-};
-
-static const struct snd_kcontrol_new broadwell_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Speaker"),
-       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
-};
-
-static const struct snd_soc_dapm_widget broadwell_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_SPK("Speaker", NULL),
-       SND_SOC_DAPM_MIC("Mic Jack", NULL),
-       SND_SOC_DAPM_MIC("DMIC1", NULL),
-       SND_SOC_DAPM_MIC("DMIC2", NULL),
-       SND_SOC_DAPM_LINE("Line Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
-
-       /* speaker */
-       {"Speaker", NULL, "SPOR"},
-       {"Speaker", NULL, "SPOL"},
-
-       /* HP jack connectors - unknown if we have jack deteck */
-       {"Headphone Jack", NULL, "HPO Pin"},
-
-       /* other jacks */
-       {"MIC1", NULL, "Mic Jack"},
-       {"LINE1", NULL, "Line Jack"},
-
-       /* digital mics */
-       {"DMIC1 Pin", NULL, "DMIC1"},
-       {"DMIC2 Pin", NULL, "DMIC2"},
-
-       /* CODEC BE connections */
-       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
-       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
-};
-
-static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       int ret = 0;
-       ret = snd_soc_jack_new(codec, "Headset",
-               SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset);
-
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&broadwell_headset,
-               ARRAY_SIZE(broadwell_headset_pins),
-               broadwell_headset_pins);
-       if (ret)
-               return ret;
-
-       rt286_mic_detect(codec, &broadwell_headset);
-       return 0;
-}
-
-
-static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
-                       struct snd_pcm_hw_params *params)
-{
-       struct snd_interval *rate = hw_param_interval(params,
-                       SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS);
-
-       /* The ADSP will covert the FE rate to 48k, stereo */
-       rate->min = rate->max = 48000;
-       channels->min = channels->max = 2;
-
-       /* set SSP0 to 16 bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S16_LE);
-       return 0;
-}
-
-static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
-               SND_SOC_CLOCK_IN);
-
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec sysclk configuration\n");
-               return ret;
-       }
-
-       return ret;
-}
-
-static struct snd_soc_ops broadwell_rt286_ops = {
-       .hw_params = broadwell_rt286_hw_params,
-};
-
-static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
-       struct sst_hsw *broadwell = pdata->dsp;
-       int ret;
-
-       /* Set ADSP SSP port settings */
-       ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
-               SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
-               SST_HSW_DEVICE_CLOCK_MASTER, 9);
-       if (ret < 0) {
-               dev_err(rtd->dev, "error: failed to set device config\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-/* broadwell digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link broadwell_rt286_dais[] = {
-       /* Front End DAI links */
-       {
-               .name = "System PCM",
-               .stream_name = "System Playback/Capture",
-               .cpu_dai_name = "System Pin",
-               .platform_name = "haswell-pcm-audio",
-               .dynamic = 1,
-               .codec_name = "snd-soc-dummy",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .init = broadwell_rtd_init,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-       },
-       {
-               .name = "Offload0",
-               .stream_name = "Offload0 Playback",
-               .cpu_dai_name = "Offload0 Pin",
-               .platform_name = "haswell-pcm-audio",
-               .dynamic = 1,
-               .codec_name = "snd-soc-dummy",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-       },
-       {
-               .name = "Offload1",
-               .stream_name = "Offload1 Playback",
-               .cpu_dai_name = "Offload1 Pin",
-               .platform_name = "haswell-pcm-audio",
-               .dynamic = 1,
-               .codec_name = "snd-soc-dummy",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-       },
-       {
-               .name = "Loopback PCM",
-               .stream_name = "Loopback",
-               .cpu_dai_name = "Loopback Pin",
-               .platform_name = "haswell-pcm-audio",
-               .dynamic = 0,
-               .codec_name = "snd-soc-dummy",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_capture = 1,
-       },
-       /* Back End DAI links */
-       {
-               /* SSP0 - Codec */
-               .name = "Codec",
-               .be_id = 0,
-               .cpu_dai_name = "snd-soc-dummy-dai",
-               .platform_name = "snd-soc-dummy",
-               .no_pcm = 1,
-               .codec_name = "i2c-INT343A:00",
-               .codec_dai_name = "rt286-aif1",
-               .init = broadwell_rt286_codec_init,
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
-               .ignore_pmdown_time = 1,
-               .be_hw_params_fixup = broadwell_ssp0_fixup,
-               .ops = &broadwell_rt286_ops,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-       },
-};
-
-/* broadwell audio machine driver for WPT + RT286S */
-static struct snd_soc_card broadwell_rt286 = {
-       .name = "broadwell-rt286",
-       .owner = THIS_MODULE,
-       .dai_link = broadwell_rt286_dais,
-       .num_links = ARRAY_SIZE(broadwell_rt286_dais),
-       .controls = broadwell_controls,
-       .num_controls = ARRAY_SIZE(broadwell_controls),
-       .dapm_widgets = broadwell_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
-       .dapm_routes = broadwell_rt286_map,
-       .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map),
-       .fully_routed = true,
-};
-
-static int broadwell_audio_probe(struct platform_device *pdev)
-{
-       broadwell_rt286.dev = &pdev->dev;
-
-       return snd_soc_register_card(&broadwell_rt286);
-}
-
-static int broadwell_audio_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_card(&broadwell_rt286);
-       return 0;
-}
-
-static struct platform_driver broadwell_audio = {
-       .probe = broadwell_audio_probe,
-       .remove = broadwell_audio_remove,
-       .driver = {
-               .name = "broadwell-audio",
-       },
-};
-
-module_platform_driver(broadwell_audio)
-
-/* Module information */
-MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
-MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:broadwell-audio");
diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c
deleted file mode 100644 (file)
index 9832afe..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Intel Baytrail SST MAX98090 machine driver
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/acpi.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
-#include <linux/slab.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include "../codecs/max98090.h"
-
-struct byt_max98090_private {
-       struct snd_soc_jack jack;
-};
-
-static const struct snd_soc_dapm_widget byt_max98090_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Int Mic", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route byt_max98090_audio_map[] = {
-       {"IN34", NULL, "Headset Mic"},
-       {"Headset Mic", NULL, "MICBIAS"},
-       {"DMICL", NULL, "Int Mic"},
-       {"Headphone", NULL, "HPL"},
-       {"Headphone", NULL, "HPR"},
-       {"Ext Spk", NULL, "SPKL"},
-       {"Ext Spk", NULL, "SPKR"},
-};
-
-static const struct snd_kcontrol_new byt_max98090_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Headphone"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Int Mic"),
-       SOC_DAPM_PIN_SWITCH("Ext Spk"),
-};
-
-static struct snd_soc_jack_pin hs_jack_pins[] = {
-       {
-               .pin    = "Headphone",
-               .mask   = SND_JACK_HEADPHONE,
-       },
-       {
-               .pin    = "Headset Mic",
-               .mask   = SND_JACK_MICROPHONE,
-       },
-};
-
-static struct snd_soc_jack_gpio hs_jack_gpios[] = {
-       {
-               .name           = "hp-gpio",
-               .idx            = 0,
-               .report         = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
-               .debounce_time  = 200,
-       },
-       {
-               .name           = "mic-gpio",
-               .idx            = 1,
-               .invert         = 1,
-               .report         = SND_JACK_MICROPHONE,
-               .debounce_time  = 200,
-       },
-};
-
-static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
-{
-       int ret;
-       struct snd_soc_codec *codec = runtime->codec;
-       struct snd_soc_card *card = runtime->card;
-       struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card);
-       struct snd_soc_jack *jack = &drv->jack;
-
-       card->dapm.idle_bias_off = true;
-
-       ret = snd_soc_dai_set_sysclk(runtime->codec_dai,
-                                    M98090_REG_SYSTEM_CLOCK,
-                                    25000000, SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               dev_err(card->dev, "Can't set codec clock %d\n", ret);
-               return ret;
-       }
-
-       /* Enable jack detection */
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_LINEOUT | SND_JACK_HEADSET, jack);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(jack, ARRAY_SIZE(hs_jack_pins),
-                                   hs_jack_pins);
-       if (ret)
-               return ret;
-
-       return snd_soc_jack_add_gpiods(card->dev->parent, jack,
-                                      ARRAY_SIZE(hs_jack_gpios),
-                                      hs_jack_gpios);
-}
-
-static struct snd_soc_dai_link byt_max98090_dais[] = {
-       {
-               .name = "Baytrail Audio",
-               .stream_name = "Audio",
-               .cpu_dai_name = "baytrail-pcm-audio",
-               .codec_dai_name = "HiFi",
-               .codec_name = "i2c-193C9890:00",
-               .platform_name = "baytrail-pcm-audio",
-               .init = byt_max98090_init,
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                          SND_SOC_DAIFMT_CBS_CFS,
-       },
-};
-
-static struct snd_soc_card byt_max98090_card = {
-       .name = "byt-max98090",
-       .dai_link = byt_max98090_dais,
-       .num_links = ARRAY_SIZE(byt_max98090_dais),
-       .dapm_widgets = byt_max98090_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(byt_max98090_widgets),
-       .dapm_routes = byt_max98090_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
-       .controls = byt_max98090_controls,
-       .num_controls = ARRAY_SIZE(byt_max98090_controls),
-       .fully_routed = true,
-};
-
-static int byt_max98090_probe(struct platform_device *pdev)
-{
-       int ret_val = 0;
-       struct byt_max98090_private *priv;
-
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
-       if (!priv) {
-               dev_err(&pdev->dev, "allocation failed\n");
-               return -ENOMEM;
-       }
-
-       byt_max98090_card.dev = &pdev->dev;
-       snd_soc_card_set_drvdata(&byt_max98090_card, priv);
-       ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card);
-       if (ret_val) {
-               dev_err(&pdev->dev,
-                       "snd_soc_register_card failed %d\n", ret_val);
-               return ret_val;
-       }
-
-       return ret_val;
-}
-
-static int byt_max98090_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-       struct byt_max98090_private *priv = snd_soc_card_get_drvdata(card);
-
-       snd_soc_jack_free_gpios(&priv->jack, ARRAY_SIZE(hs_jack_gpios),
-                               hs_jack_gpios);
-
-       return 0;
-}
-
-static struct platform_driver byt_max98090_driver = {
-       .probe = byt_max98090_probe,
-       .remove = byt_max98090_remove,
-       .driver = {
-               .name = "byt-max98090",
-               .pm = &snd_soc_pm_ops,
-       },
-};
-module_platform_driver(byt_max98090_driver)
-
-MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
-MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:byt-max98090");
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c
deleted file mode 100644 (file)
index 354eaad..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Intel Baytrail SST RT5640 machine driver
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/acpi.h>
-#include <linux/device.h>
-#include <linux/dmi.h>
-#include <linux/slab.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include "../codecs/rt5640.h"
-
-#include "sst-dsp.h"
-
-static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Internal Mic", NULL),
-       SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
-       {"Headset Mic", NULL, "MICBIAS1"},
-       {"IN2P", NULL, "Headset Mic"},
-       {"Headphone", NULL, "HPOL"},
-       {"Headphone", NULL, "HPOR"},
-       {"Speaker", NULL, "SPOLP"},
-       {"Speaker", NULL, "SPOLN"},
-       {"Speaker", NULL, "SPORP"},
-       {"Speaker", NULL, "SPORN"},
-};
-
-static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
-       {"DMIC1", NULL, "Internal Mic"},
-};
-
-static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
-       {"DMIC2", NULL, "Internal Mic"},
-};
-
-static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
-       {"Internal Mic", NULL, "MICBIAS1"},
-       {"IN1P", NULL, "Internal Mic"},
-};
-
-enum {
-       BYT_RT5640_DMIC1_MAP,
-       BYT_RT5640_DMIC2_MAP,
-       BYT_RT5640_IN1_MAP,
-};
-
-#define BYT_RT5640_MAP(quirk)  ((quirk) & 0xff)
-#define BYT_RT5640_DMIC_EN     BIT(16)
-
-static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
-                                       BYT_RT5640_DMIC_EN;
-
-static const struct snd_kcontrol_new byt_rt5640_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Headphone"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Internal Mic"),
-       SOC_DAPM_PIN_SWITCH("Speaker"),
-};
-
-static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
-                                    params_rate(params) * 256,
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               dev_err(codec_dai->dev, "can't set codec clock %d\n", ret);
-               return ret;
-       }
-       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
-                                 params_rate(params) * 64,
-                                 params_rate(params) * 256);
-       if (ret < 0) {
-               dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
-               return ret;
-       }
-       return 0;
-}
-
-static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
-{
-       byt_rt5640_quirk = (unsigned long)id->driver_data;
-       return 1;
-}
-
-static const struct dmi_system_id byt_rt5640_quirk_table[] = {
-       {
-               .callback = byt_rt5640_quirk_cb,
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
-               },
-               .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
-       },
-       {
-               .callback = byt_rt5640_quirk_cb,
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
-               },
-               .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
-                                                BYT_RT5640_DMIC_EN),
-       },
-       {}
-};
-
-static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
-{
-       int ret;
-       struct snd_soc_codec *codec = runtime->codec;
-       struct snd_soc_card *card = runtime->card;
-       const struct snd_soc_dapm_route *custom_map;
-       int num_routes;
-
-       card->dapm.idle_bias_off = true;
-
-       ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
-                                       ARRAY_SIZE(byt_rt5640_controls));
-       if (ret) {
-               dev_err(card->dev, "unable to add card controls\n");
-               return ret;
-       }
-
-       dmi_check_system(byt_rt5640_quirk_table);
-       switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
-       case BYT_RT5640_IN1_MAP:
-               custom_map = byt_rt5640_intmic_in1_map;
-               num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
-               break;
-       case BYT_RT5640_DMIC2_MAP:
-               custom_map = byt_rt5640_intmic_dmic2_map;
-               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
-               break;
-       default:
-               custom_map = byt_rt5640_intmic_dmic1_map;
-               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
-       }
-
-       ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
-       if (ret)
-               return ret;
-
-       if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
-               ret = rt5640_dmic_enable(codec, 0, 0);
-               if (ret)
-                       return ret;
-       }
-
-       snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
-       snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
-
-       return ret;
-}
-
-static struct snd_soc_ops byt_rt5640_ops = {
-       .hw_params = byt_rt5640_hw_params,
-};
-
-static struct snd_soc_dai_link byt_rt5640_dais[] = {
-       {
-               .name = "Baytrail Audio",
-               .stream_name = "Audio",
-               .cpu_dai_name = "baytrail-pcm-audio",
-               .codec_dai_name = "rt5640-aif1",
-               .codec_name = "i2c-10EC5640:00",
-               .platform_name = "baytrail-pcm-audio",
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                          SND_SOC_DAIFMT_CBS_CFS,
-               .init = byt_rt5640_init,
-               .ops = &byt_rt5640_ops,
-       },
-};
-
-static struct snd_soc_card byt_rt5640_card = {
-       .name = "byt-rt5640",
-       .dai_link = byt_rt5640_dais,
-       .num_links = ARRAY_SIZE(byt_rt5640_dais),
-       .dapm_widgets = byt_rt5640_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
-       .dapm_routes = byt_rt5640_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
-       .fully_routed = true,
-};
-
-static int byt_rt5640_probe(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = &byt_rt5640_card;
-
-       card->dev = &pdev->dev;
-       return devm_snd_soc_register_card(&pdev->dev, card);
-}
-
-static struct platform_driver byt_rt5640_audio = {
-       .probe = byt_rt5640_probe,
-       .driver = {
-               .name = "byt-rt5640",
-               .pm = &snd_soc_pm_ops,
-       },
-};
-module_platform_driver(byt_rt5640_audio)
-
-MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
-MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:byt-rt5640");
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c
deleted file mode 100644 (file)
index 5930862..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- *  byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform
- *
- *  Copyright (C) 2014 Intel Corp
- *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "../codecs/rt5640.h"
-#include "sst-atom-controls.h"
-
-static const struct snd_soc_dapm_widget byt_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Int Mic", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route byt_audio_map[] = {
-       {"IN2P", NULL, "Headset Mic"},
-       {"IN2N", NULL, "Headset Mic"},
-       {"Headset Mic", NULL, "MICBIAS1"},
-       {"IN1P", NULL, "MICBIAS1"},
-       {"LDO2", NULL, "Int Mic"},
-       {"Headphone", NULL, "HPOL"},
-       {"Headphone", NULL, "HPOR"},
-       {"Ext Spk", NULL, "SPOLP"},
-       {"Ext Spk", NULL, "SPOLN"},
-       {"Ext Spk", NULL, "SPORP"},
-       {"Ext Spk", NULL, "SPORN"},
-
-       {"AIF1 Playback", NULL, "ssp2 Tx"},
-       {"ssp2 Tx", NULL, "codec_out0"},
-       {"ssp2 Tx", NULL, "codec_out1"},
-       {"codec_in0", NULL, "ssp2 Rx"},
-       {"codec_in1", NULL, "ssp2 Rx"},
-       {"ssp2 Rx", NULL, "AIF1 Capture"},
-};
-
-static const struct snd_kcontrol_new byt_mc_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Headphone"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Int Mic"),
-       SOC_DAPM_PIN_SWITCH("Ext Spk"),
-};
-
-static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
-                                       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       snd_soc_dai_set_bclk_ratio(codec_dai, 50);
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
-                                    params_rate(params) * 512,
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec clock %d\n", ret);
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
-                                 params_rate(params) * 50,
-                                 params_rate(params) * 512);
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_pcm_stream byt_dai_params = {
-       .formats = SNDRV_PCM_FMTBIT_S24_LE,
-       .rate_min = 48000,
-       .rate_max = 48000,
-       .channels_min = 2,
-       .channels_max = 2,
-};
-
-static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
-                           struct snd_pcm_hw_params *params)
-{
-       struct snd_interval *rate = hw_param_interval(params,
-                       SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS);
-
-       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
-       rate->min = rate->max = 48000;
-       channels->min = channels->max = 2;
-
-       /* set SSP2 to 24-bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S24_LE);
-       return 0;
-}
-
-static unsigned int rates_48000[] = {
-       48000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
-       .count = ARRAY_SIZE(rates_48000),
-       .list  = rates_48000,
-};
-
-static int byt_aif1_startup(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_hw_constraint_list(substream->runtime, 0,
-                       SNDRV_PCM_HW_PARAM_RATE,
-                       &constraints_48000);
-}
-
-static struct snd_soc_ops byt_aif1_ops = {
-       .startup = byt_aif1_startup,
-};
-
-static struct snd_soc_ops byt_be_ssp2_ops = {
-       .hw_params = byt_aif1_hw_params,
-};
-
-static struct snd_soc_dai_link byt_dailink[] = {
-       [MERR_DPCM_AUDIO] = {
-               .name = "Baytrail Audio Port",
-               .stream_name = "Baytrail Audio",
-               .cpu_dai_name = "media-cpu-dai",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .codec_name = "snd-soc-dummy",
-               .platform_name = "sst-mfld-platform",
-               .ignore_suspend = 1,
-               .dynamic = 1,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               .ops = &byt_aif1_ops,
-       },
-       [MERR_DPCM_COMPR] = {
-               .name = "Baytrail Compressed Port",
-               .stream_name = "Baytrail Compress",
-               .cpu_dai_name = "compress-cpu-dai",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .codec_name = "snd-soc-dummy",
-               .platform_name = "sst-mfld-platform",
-       },
-               /* back ends */
-       {
-               .name = "SSP2-Codec",
-               .be_id = 1,
-               .cpu_dai_name = "ssp2-port",
-               .platform_name = "sst-mfld-platform",
-               .no_pcm = 1,
-               .codec_dai_name = "rt5640-aif1",
-               .codec_name = "i2c-10EC5640:00",
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-                                               | SND_SOC_DAIFMT_CBS_CFS,
-               .be_hw_params_fixup = byt_codec_fixup,
-               .ignore_suspend = 1,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               .ops = &byt_be_ssp2_ops,
-       },
-};
-
-/* SoC card */
-static struct snd_soc_card snd_soc_card_byt = {
-       .name = "baytrailcraudio",
-       .dai_link = byt_dailink,
-       .num_links = ARRAY_SIZE(byt_dailink),
-       .dapm_widgets = byt_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets),
-       .dapm_routes = byt_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(byt_audio_map),
-       .controls = byt_mc_controls,
-       .num_controls = ARRAY_SIZE(byt_mc_controls),
-};
-
-static int snd_byt_mc_probe(struct platform_device *pdev)
-{
-       int ret_val = 0;
-
-       /* register the soc card */
-       snd_soc_card_byt.dev = &pdev->dev;
-
-       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt);
-       if (ret_val) {
-               dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val);
-               return ret_val;
-       }
-       platform_set_drvdata(pdev, &snd_soc_card_byt);
-       return ret_val;
-}
-
-static struct platform_driver snd_byt_mc_driver = {
-       .driver = {
-               .name = "bytt100_rt5640",
-               .pm = &snd_soc_pm_ops,
-       },
-       .probe = snd_byt_mc_probe,
-};
-
-module_platform_driver(snd_byt_mc_driver);
-
-MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
-MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:bytt100_rt5640");
diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c
deleted file mode 100644 (file)
index bd29617..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *  cht-bsw-rt5645.c - ASoc Machine driver for Intel Cherryview-based platforms
- *                     Cherrytrail and Braswell, with RT5645 codec.
- *
- *  Copyright (C) 2015 Intel Corp
- *  Author: Fang, Yang A <yang.a.fang@intel.com>
- *             N,Harshapriya <harshapriya.n@intel.com>
- *  This file is modified from cht_bsw_rt5672.c
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include "../codecs/rt5645.h"
-#include "sst-atom-controls.h"
-
-#define CHT_PLAT_CLK_3_HZ      19200000
-#define CHT_CODEC_DAI  "rt5645-aif1"
-
-struct cht_mc_private {
-       struct snd_soc_jack hp_jack;
-       struct snd_soc_jack mic_jack;
-};
-
-static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
-{
-       int i;
-
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd;
-
-               rtd = card->rtd + i;
-               if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
-                            strlen(CHT_CODEC_DAI)))
-                       return rtd->codec_dai;
-       }
-       return NULL;
-}
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *k, int  event)
-{
-       struct snd_soc_dapm_context *dapm = w->dapm;
-       struct snd_soc_card *card = dapm->card;
-       struct snd_soc_dai *codec_dai;
-       int ret;
-
-       codec_dai = cht_get_codec_dai(card);
-       if (!codec_dai) {
-               dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
-               return -EIO;
-       }
-
-       if (!SND_SOC_DAPM_EVENT_OFF(event))
-               return 0;
-
-       /* Set codec sysclk source to its internal clock because codec PLL will
-        * be off when idle and MCLK will also be off by ACPI when codec is
-        * runtime suspended. Codec needs clock for jack detection and button
-        * press.
-        */
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
-                       0, SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Int Mic", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
-                       platform_clock_control, SND_SOC_DAPM_POST_PMD),
-};
-
-static const struct snd_soc_dapm_route cht_audio_map[] = {
-       {"IN1P", NULL, "Headset Mic"},
-       {"IN1N", NULL, "Headset Mic"},
-       {"DMIC L1", NULL, "Int Mic"},
-       {"DMIC R1", NULL, "Int Mic"},
-       {"Headphone", NULL, "HPOL"},
-       {"Headphone", NULL, "HPOR"},
-       {"Ext Spk", NULL, "SPOL"},
-       {"Ext Spk", NULL, "SPOR"},
-       {"AIF1 Playback", NULL, "ssp2 Tx"},
-       {"ssp2 Tx", NULL, "codec_out0"},
-       {"ssp2 Tx", NULL, "codec_out1"},
-       {"codec_in0", NULL, "ssp2 Rx" },
-       {"codec_in1", NULL, "ssp2 Rx" },
-       {"ssp2 Rx", NULL, "AIF1 Capture"},
-       {"Headphone", NULL, "Platform Clock"},
-       {"Headset Mic", NULL, "Platform Clock"},
-       {"Int Mic", NULL, "Platform Clock"},
-       {"Ext Spk", NULL, "Platform Clock"},
-};
-
-static const struct snd_kcontrol_new cht_mc_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Headphone"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Int Mic"),
-       SOC_DAPM_PIN_SWITCH("Ext Spk"),
-};
-
-static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
-       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
-                                 CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1,
-                               params_rate(params) * 512, SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
-{
-       int ret;
-       struct snd_soc_codec *codec = runtime->codec;
-       struct snd_soc_dai *codec_dai = runtime->codec_dai;
-       struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
-
-       /* Select clk_i2s1_asrc as ASRC clock source */
-       rt5645_sel_asrc_clk_src(codec,
-                               RT5645_DA_STEREO_FILTER |
-                               RT5645_DA_MONO_L_FILTER |
-                               RT5645_DA_MONO_R_FILTER |
-                               RT5645_AD_STEREO_FILTER,
-                               RT5645_CLK_SEL_I2S1_ASRC);
-
-       /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
-       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
-       if (ret < 0) {
-               dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
-               return ret;
-       }
-
-       ret = snd_soc_jack_new(codec, "Headphone Jack",
-                               SND_JACK_HEADPHONE,
-                               &ctx->hp_jack);
-       if (ret) {
-               dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
-               return ret;
-       }
-
-       ret = snd_soc_jack_new(codec, "Mic Jack",
-                               SND_JACK_MICROPHONE,
-                               &ctx->mic_jack);
-       if (ret) {
-               dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
-               return ret;
-       }
-
-       rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack);
-
-       return ret;
-}
-
-static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
-                           struct snd_pcm_hw_params *params)
-{
-       struct snd_interval *rate = hw_param_interval(params,
-                       SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS);
-
-       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
-       rate->min = rate->max = 48000;
-       channels->min = channels->max = 2;
-
-       /* set SSP2 to 24-bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S24_LE);
-       return 0;
-}
-
-static unsigned int rates_48000[] = {
-       48000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
-       .count = ARRAY_SIZE(rates_48000),
-       .list  = rates_48000,
-};
-
-static int cht_aif1_startup(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_hw_constraint_list(substream->runtime, 0,
-                       SNDRV_PCM_HW_PARAM_RATE,
-                       &constraints_48000);
-}
-
-static struct snd_soc_ops cht_aif1_ops = {
-       .startup = cht_aif1_startup,
-};
-
-static struct snd_soc_ops cht_be_ssp2_ops = {
-       .hw_params = cht_aif1_hw_params,
-};
-
-static struct snd_soc_dai_link cht_dailink[] = {
-       [MERR_DPCM_AUDIO] = {
-               .name = "Audio Port",
-               .stream_name = "Audio",
-               .cpu_dai_name = "media-cpu-dai",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .codec_name = "snd-soc-dummy",
-               .platform_name = "sst-mfld-platform",
-               .ignore_suspend = 1,
-               .dynamic = 1,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               .ops = &cht_aif1_ops,
-       },
-       [MERR_DPCM_COMPR] = {
-               .name = "Compressed Port",
-               .stream_name = "Compress",
-               .cpu_dai_name = "compress-cpu-dai",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .codec_name = "snd-soc-dummy",
-               .platform_name = "sst-mfld-platform",
-       },
-       /* CODEC<->CODEC link */
-       /* back ends */
-       {
-               .name = "SSP2-Codec",
-               .be_id = 1,
-               .cpu_dai_name = "ssp2-port",
-               .platform_name = "sst-mfld-platform",
-               .no_pcm = 1,
-               .codec_dai_name = "rt5645-aif1",
-               .codec_name = "i2c-10EC5645:00",
-               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
-                                       | SND_SOC_DAIFMT_CBS_CFS,
-               .init = cht_codec_init,
-               .be_hw_params_fixup = cht_codec_fixup,
-               .ignore_suspend = 1,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               .ops = &cht_be_ssp2_ops,
-       },
-};
-
-/* SoC card */
-static struct snd_soc_card snd_soc_card_cht = {
-       .name = "chtrt5645",
-       .dai_link = cht_dailink,
-       .num_links = ARRAY_SIZE(cht_dailink),
-       .dapm_widgets = cht_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
-       .dapm_routes = cht_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
-       .controls = cht_mc_controls,
-       .num_controls = ARRAY_SIZE(cht_mc_controls),
-};
-
-static int snd_cht_mc_probe(struct platform_device *pdev)
-{
-       int ret_val = 0;
-       struct cht_mc_private *drv;
-
-       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
-       if (!drv)
-               return -ENOMEM;
-
-       snd_soc_card_cht.dev = &pdev->dev;
-       snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
-       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
-       if (ret_val) {
-               dev_err(&pdev->dev,
-                       "snd_soc_register_card failed %d\n", ret_val);
-               return ret_val;
-       }
-       platform_set_drvdata(pdev, &snd_soc_card_cht);
-       return ret_val;
-}
-
-static struct platform_driver snd_cht_mc_driver = {
-       .driver = {
-               .name = "cht-bsw-rt5645",
-               .pm = &snd_soc_pm_ops,
-       },
-       .probe = snd_cht_mc_probe,
-};
-
-module_platform_driver(snd_cht_mc_driver)
-
-MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
-MODULE_AUTHOR("Fang, Yang A,N,Harshapriya");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:cht-bsw-rt5645");
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c
deleted file mode 100644 (file)
index ff01662..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- *  cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms
- *                     Cherrytrail and Braswell, with RT5672 codec.
- *
- *  Copyright (C) 2014 Intel Corp
- *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
- *          Mengdong Lin <mengdong.lin@intel.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "../codecs/rt5670.h"
-#include "sst-atom-controls.h"
-
-/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */
-#define CHT_PLAT_CLK_3_HZ      19200000
-#define CHT_CODEC_DAI  "rt5670-aif1"
-
-static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
-{
-       int i;
-
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_pcm_runtime *rtd;
-
-               rtd = card->rtd + i;
-               if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
-                            strlen(CHT_CODEC_DAI)))
-                       return rtd->codec_dai;
-       }
-       return NULL;
-}
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *k, int  event)
-{
-       struct snd_soc_dapm_context *dapm = w->dapm;
-       struct snd_soc_card *card = dapm->card;
-       struct snd_soc_dai *codec_dai;
-
-       codec_dai = cht_get_codec_dai(card);
-       if (!codec_dai) {
-               dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
-               return -EIO;
-       }
-
-       if (!SND_SOC_DAPM_EVENT_OFF(event))
-               return 0;
-
-       /* Set codec sysclk source to its internal clock because codec PLL will
-        * be off when idle and MCLK will also be off by ACPI when codec is
-        * runtime suspended. Codec needs clock for jack detection and button
-        * press.
-        */
-       snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
-                              0, SND_SOC_CLOCK_IN);
-
-       return 0;
-}
-
-static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Int Mic", NULL),
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
-                       platform_clock_control, SND_SOC_DAPM_POST_PMD),
-};
-
-static const struct snd_soc_dapm_route cht_audio_map[] = {
-       {"IN1P", NULL, "Headset Mic"},
-       {"IN1N", NULL, "Headset Mic"},
-       {"DMIC L1", NULL, "Int Mic"},
-       {"DMIC R1", NULL, "Int Mic"},
-       {"Headphone", NULL, "HPOL"},
-       {"Headphone", NULL, "HPOR"},
-       {"Ext Spk", NULL, "SPOLP"},
-       {"Ext Spk", NULL, "SPOLN"},
-       {"Ext Spk", NULL, "SPORP"},
-       {"Ext Spk", NULL, "SPORN"},
-       {"AIF1 Playback", NULL, "ssp2 Tx"},
-       {"ssp2 Tx", NULL, "codec_out0"},
-       {"ssp2 Tx", NULL, "codec_out1"},
-       {"codec_in0", NULL, "ssp2 Rx"},
-       {"codec_in1", NULL, "ssp2 Rx"},
-       {"ssp2 Rx", NULL, "AIF1 Capture"},
-       {"Headphone", NULL, "Platform Clock"},
-       {"Headset Mic", NULL, "Platform Clock"},
-       {"Int Mic", NULL, "Platform Clock"},
-       {"Ext Spk", NULL, "Platform Clock"},
-};
-
-static const struct snd_kcontrol_new cht_mc_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Headphone"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Int Mic"),
-       SOC_DAPM_PIN_SWITCH("Ext Spk"),
-};
-
-static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
-                                       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
-       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
-                                 CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
-               return ret;
-       }
-
-       /* set codec sysclk source to PLL */
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
-                                    params_rate(params) * 512,
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
-               return ret;
-       }
-       return 0;
-}
-
-static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
-{
-       int ret;
-       struct snd_soc_dai *codec_dai = runtime->codec_dai;
-       struct snd_soc_codec *codec = codec_dai->codec;
-
-       /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
-       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
-       if (ret < 0) {
-               dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
-               return ret;
-       }
-
-       /* Select codec ASRC clock source to track I2S1 clock, because codec
-        * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
-        * be supported by RT5672. Otherwise, ASRC will be disabled and cause
-        * noise.
-        */
-       rt5670_sel_asrc_clk_src(codec,
-                               RT5670_DA_STEREO_FILTER
-                               | RT5670_DA_MONO_L_FILTER
-                               | RT5670_DA_MONO_R_FILTER
-                               | RT5670_AD_STEREO_FILTER
-                               | RT5670_AD_MONO_L_FILTER
-                               | RT5670_AD_MONO_R_FILTER,
-                               RT5670_CLK_SEL_I2S1_ASRC);
-       return 0;
-}
-
-static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
-                           struct snd_pcm_hw_params *params)
-{
-       struct snd_interval *rate = hw_param_interval(params,
-                       SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS);
-
-       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
-       rate->min = rate->max = 48000;
-       channels->min = channels->max = 2;
-
-       /* set SSP2 to 24-bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S24_LE);
-       return 0;
-}
-
-static unsigned int rates_48000[] = {
-       48000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
-       .count = ARRAY_SIZE(rates_48000),
-       .list  = rates_48000,
-};
-
-static int cht_aif1_startup(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_hw_constraint_list(substream->runtime, 0,
-                       SNDRV_PCM_HW_PARAM_RATE,
-                       &constraints_48000);
-}
-
-static struct snd_soc_ops cht_aif1_ops = {
-       .startup = cht_aif1_startup,
-};
-
-static struct snd_soc_ops cht_be_ssp2_ops = {
-       .hw_params = cht_aif1_hw_params,
-};
-
-static struct snd_soc_dai_link cht_dailink[] = {
-       /* Front End DAI links */
-       [MERR_DPCM_AUDIO] = {
-               .name = "Audio Port",
-               .stream_name = "Audio",
-               .cpu_dai_name = "media-cpu-dai",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .codec_name = "snd-soc-dummy",
-               .platform_name = "sst-mfld-platform",
-               .ignore_suspend = 1,
-               .dynamic = 1,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               .ops = &cht_aif1_ops,
-       },
-       [MERR_DPCM_COMPR] = {
-               .name = "Compressed Port",
-               .stream_name = "Compress",
-               .cpu_dai_name = "compress-cpu-dai",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .codec_name = "snd-soc-dummy",
-               .platform_name = "sst-mfld-platform",
-       },
-
-       /* Back End DAI links */
-       {
-               /* SSP2 - Codec */
-               .name = "SSP2-Codec",
-               .be_id = 1,
-               .cpu_dai_name = "ssp2-port",
-               .platform_name = "sst-mfld-platform",
-               .no_pcm = 1,
-               .codec_dai_name = "rt5670-aif1",
-               .codec_name = "i2c-10EC5670:00",
-               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
-                                       | SND_SOC_DAIFMT_CBS_CFS,
-               .init = cht_codec_init,
-               .be_hw_params_fixup = cht_codec_fixup,
-               .ignore_suspend = 1,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               .ops = &cht_be_ssp2_ops,
-       },
-};
-
-/* SoC card */
-static struct snd_soc_card snd_soc_card_cht = {
-       .name = "cherrytrailcraudio",
-       .dai_link = cht_dailink,
-       .num_links = ARRAY_SIZE(cht_dailink),
-       .dapm_widgets = cht_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
-       .dapm_routes = cht_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
-       .controls = cht_mc_controls,
-       .num_controls = ARRAY_SIZE(cht_mc_controls),
-};
-
-static int snd_cht_mc_probe(struct platform_device *pdev)
-{
-       int ret_val = 0;
-
-       /* register the soc card */
-       snd_soc_card_cht.dev = &pdev->dev;
-       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
-       if (ret_val) {
-               dev_err(&pdev->dev,
-                       "snd_soc_register_card failed %d\n", ret_val);
-               return ret_val;
-       }
-       platform_set_drvdata(pdev, &snd_soc_card_cht);
-       return ret_val;
-}
-
-static struct platform_driver snd_cht_mc_driver = {
-       .driver = {
-               .name = "cht-bsw-rt5672",
-               .pm = &snd_soc_pm_ops,
-       },
-       .probe = snd_cht_mc_probe,
-};
-
-module_platform_driver(snd_cht_mc_driver);
-
-MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
-MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:cht-bsw-rt5672");
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
new file mode 100644 (file)
index 0000000..f24154c
--- /dev/null
@@ -0,0 +1,7 @@
+snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
+snd-soc-sst-acpi-objs := sst-acpi.o
+snd-soc-sst-ipc-objs := sst-ipc.o
+
+obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
+obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
+
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c
new file mode 100644 (file)
index 0000000..42f293f
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Intel SST loader on ACPI systems
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "sst-dsp.h"
+
+#define SST_LPT_DSP_DMA_ADDR_OFFSET    0x0F0000
+#define SST_WPT_DSP_DMA_ADDR_OFFSET    0x0FE000
+#define SST_LPT_DSP_DMA_SIZE           (1024 - 1)
+
+/* Descriptor for SST ASoC machine driver */
+struct sst_acpi_mach {
+       /* ACPI ID for the matching machine driver. Audio codec for instance */
+       const u8 id[ACPI_ID_LEN];
+       /* machine driver name */
+       const char *drv_name;
+       /* firmware file name */
+       const char *fw_filename;
+};
+
+/* Descriptor for setting up SST platform data */
+struct sst_acpi_desc {
+       const char *drv_name;
+       struct sst_acpi_mach *machines;
+       /* Platform resource indexes. Must set to -1 if not used */
+       int resindex_lpe_base;
+       int resindex_pcicfg_base;
+       int resindex_fw_base;
+       int irqindex_host_ipc;
+       int resindex_dma_base;
+       /* Unique number identifying the SST core on platform */
+       int sst_id;
+       /* DMA only valid when resindex_dma_base != -1*/
+       int dma_engine;
+       int dma_size;
+};
+
+struct sst_acpi_priv {
+       struct platform_device *pdev_mach;
+       struct platform_device *pdev_pcm;
+       struct sst_pdata sst_pdata;
+       struct sst_acpi_desc *desc;
+       struct sst_acpi_mach *mach;
+};
+
+static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
+{
+       struct platform_device *pdev = context;
+       struct device *dev = &pdev->dev;
+       struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
+       struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
+       struct sst_acpi_desc *desc = sst_acpi->desc;
+       struct sst_acpi_mach *mach = sst_acpi->mach;
+
+       sst_pdata->fw = fw;
+       if (!fw) {
+               dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
+               return;
+       }
+
+       /* register PCM and DAI driver */
+       sst_acpi->pdev_pcm =
+               platform_device_register_data(dev, desc->drv_name, -1,
+                                             sst_pdata, sizeof(*sst_pdata));
+       if (IS_ERR(sst_acpi->pdev_pcm)) {
+               dev_err(dev, "Cannot register device %s. Error %d\n",
+                       desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
+       }
+
+       return;
+}
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+                                      void *context, void **ret)
+{
+       *(bool *)context = true;
+       return AE_OK;
+}
+
+static struct sst_acpi_mach *sst_acpi_find_machine(
+       struct sst_acpi_mach *machines)
+{
+       struct sst_acpi_mach *mach;
+       bool found = false;
+
+       for (mach = machines; mach->id[0]; mach++)
+               if (ACPI_SUCCESS(acpi_get_devices(mach->id,
+                                                 sst_acpi_mach_match,
+                                                 &found, NULL)) && found)
+                       return mach;
+
+       return NULL;
+}
+
+static int sst_acpi_probe(struct platform_device *pdev)
+{
+       const struct acpi_device_id *id;
+       struct device *dev = &pdev->dev;
+       struct sst_acpi_priv *sst_acpi;
+       struct sst_pdata *sst_pdata;
+       struct sst_acpi_mach *mach;
+       struct sst_acpi_desc *desc;
+       struct resource *mmio;
+       int ret = 0;
+
+       sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
+       if (sst_acpi == NULL)
+               return -ENOMEM;
+
+       id = acpi_match_device(dev->driver->acpi_match_table, dev);
+       if (!id)
+               return -ENODEV;
+
+       desc = (struct sst_acpi_desc *)id->driver_data;
+       mach = sst_acpi_find_machine(desc->machines);
+       if (mach == NULL) {
+               dev_err(dev, "No matching ASoC machine driver found\n");
+               return -ENODEV;
+       }
+
+       sst_pdata = &sst_acpi->sst_pdata;
+       sst_pdata->id = desc->sst_id;
+       sst_pdata->dma_dev = dev;
+       sst_acpi->desc = desc;
+       sst_acpi->mach = mach;
+
+       sst_pdata->resindex_dma_base = desc->resindex_dma_base;
+       if (desc->resindex_dma_base >= 0) {
+               sst_pdata->dma_engine = desc->dma_engine;
+               sst_pdata->dma_base = desc->resindex_dma_base;
+               sst_pdata->dma_size = desc->dma_size;
+       }
+
+       if (desc->irqindex_host_ipc >= 0)
+               sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
+
+       if (desc->resindex_lpe_base >= 0) {
+               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+                                            desc->resindex_lpe_base);
+               if (mmio) {
+                       sst_pdata->lpe_base = mmio->start;
+                       sst_pdata->lpe_size = resource_size(mmio);
+               }
+       }
+
+       if (desc->resindex_pcicfg_base >= 0) {
+               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+                                            desc->resindex_pcicfg_base);
+               if (mmio) {
+                       sst_pdata->pcicfg_base = mmio->start;
+                       sst_pdata->pcicfg_size = resource_size(mmio);
+               }
+       }
+
+       if (desc->resindex_fw_base >= 0) {
+               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+                                            desc->resindex_fw_base);
+               if (mmio) {
+                       sst_pdata->fw_base = mmio->start;
+                       sst_pdata->fw_size = resource_size(mmio);
+               }
+       }
+
+       platform_set_drvdata(pdev, sst_acpi);
+
+       /* register machine driver */
+       sst_acpi->pdev_mach =
+               platform_device_register_data(dev, mach->drv_name, -1,
+                                             sst_pdata, sizeof(*sst_pdata));
+       if (IS_ERR(sst_acpi->pdev_mach))
+               return PTR_ERR(sst_acpi->pdev_mach);
+
+       /* continue SST probing after firmware is loaded */
+       ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
+                                     dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
+       if (ret)
+               platform_device_unregister(sst_acpi->pdev_mach);
+
+       return ret;
+}
+
+static int sst_acpi_remove(struct platform_device *pdev)
+{
+       struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
+       struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
+
+       platform_device_unregister(sst_acpi->pdev_mach);
+       if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
+               platform_device_unregister(sst_acpi->pdev_pcm);
+       release_firmware(sst_pdata->fw);
+
+       return 0;
+}
+
+static struct sst_acpi_mach haswell_machines[] = {
+       { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
+       {}
+};
+
+static struct sst_acpi_desc sst_acpi_haswell_desc = {
+       .drv_name = "haswell-pcm-audio",
+       .machines = haswell_machines,
+       .resindex_lpe_base = 0,
+       .resindex_pcicfg_base = 1,
+       .resindex_fw_base = -1,
+       .irqindex_host_ipc = 0,
+       .sst_id = SST_DEV_ID_LYNX_POINT,
+       .dma_engine = SST_DMA_TYPE_DW,
+       .resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
+       .dma_size = SST_LPT_DSP_DMA_SIZE,
+};
+
+static struct sst_acpi_mach broadwell_machines[] = {
+       { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
+       {}
+};
+
+static struct sst_acpi_desc sst_acpi_broadwell_desc = {
+       .drv_name = "haswell-pcm-audio",
+       .machines = broadwell_machines,
+       .resindex_lpe_base = 0,
+       .resindex_pcicfg_base = 1,
+       .resindex_fw_base = -1,
+       .irqindex_host_ipc = 0,
+       .sst_id = SST_DEV_ID_WILDCAT_POINT,
+       .dma_engine = SST_DMA_TYPE_DW,
+       .resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
+       .dma_size = SST_LPT_DSP_DMA_SIZE,
+};
+
+static struct sst_acpi_mach baytrail_machines[] = {
+       { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
+       { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
+       {}
+};
+
+static struct sst_acpi_desc sst_acpi_baytrail_desc = {
+       .drv_name = "baytrail-pcm-audio",
+       .machines = baytrail_machines,
+       .resindex_lpe_base = 0,
+       .resindex_pcicfg_base = 1,
+       .resindex_fw_base = 2,
+       .irqindex_host_ipc = 5,
+       .sst_id = SST_DEV_ID_BYT,
+       .resindex_dma_base = -1,
+};
+
+static struct acpi_device_id sst_acpi_match[] = {
+       { "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
+       { "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
+       { "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
+
+static struct platform_driver sst_acpi_driver = {
+       .probe = sst_acpi_probe,
+       .remove = sst_acpi_remove,
+       .driver = {
+               .name = "sst-acpi",
+               .acpi_match_table = ACPI_PTR(sst_acpi_match),
+       },
+};
+module_platform_driver(sst_acpi_driver);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
+MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
new file mode 100644 (file)
index 0000000..396d545
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Intel Smart Sound Technology
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SOUND_SOC_SST_DSP_PRIV_H
+#define __SOUND_SOC_SST_DSP_PRIV_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+
+struct sst_mem_block;
+struct sst_module;
+struct sst_fw;
+
+/* do we need to remove or keep */
+#define DSP_DRAM_ADDR_OFFSET           0x400000
+
+/*
+ * DSP Operations exported by platform Audio DSP driver.
+ */
+struct sst_ops {
+       /* DSP core boot / reset */
+       void (*boot)(struct sst_dsp *);
+       void (*reset)(struct sst_dsp *);
+       int (*wake)(struct sst_dsp *);
+       void (*sleep)(struct sst_dsp *);
+       void (*stall)(struct sst_dsp *);
+
+       /* Shim IO */
+       void (*write)(void __iomem *addr, u32 offset, u32 value);
+       u32 (*read)(void __iomem *addr, u32 offset);
+       void (*write64)(void __iomem *addr, u32 offset, u64 value);
+       u64 (*read64)(void __iomem *addr, u32 offset);
+
+       /* DSP I/DRAM IO */
+       void (*ram_read)(struct sst_dsp *sst, void  *dest, void __iomem *src,
+               size_t bytes);
+       void (*ram_write)(struct sst_dsp *sst, void __iomem *dest, void *src,
+               size_t bytes);
+
+       void (*dump)(struct sst_dsp *);
+
+       /* IRQ handlers */
+       irqreturn_t (*irq_handler)(int irq, void *context);
+
+       /* SST init and free */
+       int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata);
+       void (*free)(struct sst_dsp *sst);
+
+       /* FW module parser/loader */
+       int (*parse_fw)(struct sst_fw *sst_fw);
+};
+
+/*
+ * Audio DSP memory offsets and addresses.
+ */
+struct sst_addr {
+       u32 lpe_base;
+       u32 shim_offset;
+       u32 iram_offset;
+       u32 dram_offset;
+       u32 dsp_iram_offset;
+       u32 dsp_dram_offset;
+       void __iomem *lpe;
+       void __iomem *shim;
+       void __iomem *pci_cfg;
+       void __iomem *fw_ext;
+};
+
+/*
+ * Audio DSP Mailbox configuration.
+ */
+struct sst_mailbox {
+       void __iomem *in_base;
+       void __iomem *out_base;
+       size_t in_size;
+       size_t out_size;
+};
+
+/*
+ * Audio DSP memory block types.
+ */
+enum sst_mem_type {
+       SST_MEM_IRAM = 0,
+       SST_MEM_DRAM = 1,
+       SST_MEM_ANY  = 2,
+       SST_MEM_CACHE= 3,
+};
+
+/*
+ * Audio DSP Generic Firmware File.
+ *
+ * SST Firmware files can consist of 1..N modules. This generic structure is
+ * used to manage each firmware file and it's modules regardless of SST firmware
+ * type. A SST driver may load multiple FW files.
+ */
+struct sst_fw {
+       struct sst_dsp *dsp;
+
+       /* base addresses of FW file data */
+       dma_addr_t dmable_fw_paddr;     /* physical address of fw data */
+       void *dma_buf;                  /* virtual address of fw data */
+       u32 size;                       /* size of fw data */
+
+       /* lists */
+       struct list_head list;          /* DSP list of FW */
+       struct list_head module_list;   /* FW list of modules */
+
+       void *private;                  /* core doesn't touch this */
+};
+
+/*
+ * Audio DSP Generic Module Template.
+ *
+ * Used to define and register a new FW module. This data is extracted from
+ * FW module header information.
+ */
+struct sst_module_template {
+       u32 id;
+       u32 entry;                      /* entry point */
+       u32 scratch_size;
+       u32 persistent_size;
+};
+
+/*
+ * Block Allocator - Used to allocate blocks of DSP memory.
+ */
+struct sst_block_allocator {
+       u32 id;
+       u32 offset;
+       int size;
+       enum sst_mem_type type;
+};
+
+/*
+ * Runtime Module Instance - A module object can be instanciated multiple
+ * times within the DSP FW.
+ */
+struct sst_module_runtime {
+       struct sst_dsp *dsp;
+       int id;
+       struct sst_module *module;      /* parent module we belong too */
+
+       u32 persistent_offset;          /* private memory offset */
+       void *private;
+
+       struct list_head list;
+       struct list_head block_list;    /* list of blocks used */
+};
+
+/*
+ * Runtime Module Context - The runtime context must be manually stored by the
+ * driver prior to enter S3 and restored after leaving S3. This should really be
+ * part of the memory context saved by the enter D3 message IPC ???
+ */
+struct sst_module_runtime_context {
+       dma_addr_t dma_buffer;
+       u32 *buffer;
+};
+
+/*
+ * Audio DSP Module State
+ */
+enum sst_module_state {
+       SST_MODULE_STATE_UNLOADED = 0,  /* default state */
+       SST_MODULE_STATE_LOADED,
+       SST_MODULE_STATE_INITIALIZED,   /* and inactive */
+       SST_MODULE_STATE_ACTIVE,
+};
+
+/*
+ * Audio DSP Generic Module.
+ *
+ * Each Firmware file can consist of 1..N modules. A module can span multiple
+ * ADSP memory blocks. The simplest FW will be a file with 1 module. A module
+ * can be instanciated multiple times in the DSP.
+ */
+struct sst_module {
+       struct sst_dsp *dsp;
+       struct sst_fw *sst_fw;          /* parent FW we belong too */
+
+       /* module configuration */
+       u32 id;
+       u32 entry;                      /* module entry point */
+       s32 offset;                     /* module offset in firmware file */
+       u32 size;                       /* module size */
+       u32 scratch_size;               /* global scratch memory required */
+       u32 persistent_size;            /* private memory required */
+       enum sst_mem_type type;         /* destination memory type */
+       u32 data_offset;                /* offset in ADSP memory space */
+       void *data;                     /* module data */
+
+       /* runtime */
+       u32 usage_count;                /* can be unloaded if count == 0 */
+       void *private;                  /* core doesn't touch this */
+
+       /* lists */
+       struct list_head block_list;    /* Module list of blocks in use */
+       struct list_head list;          /* DSP list of modules */
+       struct list_head list_fw;       /* FW list of modules */
+       struct list_head runtime_list;  /* list of runtime module objects*/
+
+       /* state */
+       enum sst_module_state state;
+};
+
+/*
+ * SST Memory Block operations.
+ */
+struct sst_block_ops {
+       int (*enable)(struct sst_mem_block *block);
+       int (*disable)(struct sst_mem_block *block);
+};
+
+/*
+ * SST Generic Memory Block.
+ *
+ * SST ADP  memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be
+ * power gated.
+ */
+struct sst_mem_block {
+       struct sst_dsp *dsp;
+       struct sst_module *module;      /* module that uses this block */
+
+       /* block config */
+       u32 offset;                     /* offset from base */
+       u32 size;                       /* block size */
+       u32 index;                      /* block index 0..N */
+       enum sst_mem_type type;         /* block memory type IRAM/DRAM */
+       struct sst_block_ops *ops;      /* block operations, if any */
+
+       /* block status */
+       u32 bytes_used;                 /* bytes in use by modules */
+       void *private;                  /* generic core does not touch this */
+       int users;                      /* number of modules using this block */
+
+       /* block lists */
+       struct list_head module_list;   /* Module list of blocks */
+       struct list_head list;          /* Map list of free/used blocks */
+};
+
+/*
+ * Generic SST Shim Interface.
+ */
+struct sst_dsp {
+
+       /* runtime */
+       struct sst_dsp_device *sst_dev;
+       spinlock_t spinlock;    /* IPC locking */
+       struct mutex mutex;     /* DSP FW lock */
+       struct device *dev;
+       struct device *dma_dev;
+       void *thread_context;
+       int irq;
+       u32 id;
+
+       /* list of free and used ADSP memory blocks */
+       struct list_head used_block_list;
+       struct list_head free_block_list;
+
+       /* operations */
+       struct sst_ops *ops;
+
+       /* debug FS */
+       struct dentry *debugfs_root;
+
+       /* base addresses */
+       struct sst_addr addr;
+
+       /* mailbox */
+       struct sst_mailbox mailbox;
+
+       /* SST FW files loaded and their modules */
+       struct list_head module_list;
+       struct list_head fw_list;
+
+       /* scratch buffer */
+       struct list_head scratch_block_list;
+       u32 scratch_offset;
+       u32 scratch_size;
+
+       /* platform data */
+       struct sst_pdata *pdata;
+
+       /* DMA FW loading */
+       struct sst_dma *dma;
+       bool fw_use_dma;
+};
+
+/* Size optimised DRAM/IRAM memcpy */
+static inline void sst_dsp_write(struct sst_dsp *sst, void *src,
+       u32 dest_offset, size_t bytes)
+{
+       sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes);
+}
+
+static inline void sst_dsp_read(struct sst_dsp *sst, void *dest,
+       u32 src_offset, size_t bytes)
+{
+       sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes);
+}
+
+static inline void *sst_dsp_get_thread_context(struct sst_dsp *sst)
+{
+       return sst->thread_context;
+}
+
+/* Create/Free FW files - can contain multiple modules */
+struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
+       const struct firmware *fw, void *private);
+void sst_fw_free(struct sst_fw *sst_fw);
+void sst_fw_free_all(struct sst_dsp *dsp);
+int sst_fw_reload(struct sst_fw *sst_fw);
+void sst_fw_unload(struct sst_fw *sst_fw);
+
+/* Create/Free firmware modules */
+struct sst_module *sst_module_new(struct sst_fw *sst_fw,
+       struct sst_module_template *template, void *private);
+void sst_module_free(struct sst_module *module);
+struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
+int sst_module_alloc_blocks(struct sst_module *module);
+int sst_module_free_blocks(struct sst_module *module);
+
+/* Create/Free firmware module runtime instances */
+struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module,
+       int id, void *private);
+void sst_module_runtime_free(struct sst_module_runtime *runtime);
+struct sst_module_runtime *sst_module_runtime_get_from_id(
+       struct sst_module *module, u32 id);
+int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
+       int offset);
+int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime);
+int sst_module_runtime_save(struct sst_module_runtime *runtime,
+       struct sst_module_runtime_context *context);
+int sst_module_runtime_restore(struct sst_module_runtime *runtime,
+       struct sst_module_runtime_context *context);
+
+/* generic block allocation */
+int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba,
+       struct list_head *block_list);
+int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list);
+
+/* scratch allocation */
+int sst_block_alloc_scratch(struct sst_dsp *dsp);
+void sst_block_free_scratch(struct sst_dsp *dsp);
+
+/* Register the DSPs memory blocks - would be nice to read from ACPI */
+struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
+       u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
+       void *private);
+void sst_mem_block_unregister_all(struct sst_dsp *dsp);
+
+/* Create/Free DMA resources */
+int sst_dma_new(struct sst_dsp *sst);
+void sst_dma_free(struct sst_dma *dma);
+
+u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
+       enum sst_mem_type type);
+#endif
diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c
new file mode 100644 (file)
index 0000000..64e9421
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * Intel Smart Sound Technology (SST) DSP Core Driver
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/intel-sst.h>
+
+/* Internal generic low-level SST IO functions - can be overidden */
+void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
+{
+       writel(value, addr + offset);
+}
+EXPORT_SYMBOL_GPL(sst_shim32_write);
+
+u32 sst_shim32_read(void __iomem *addr, u32 offset)
+{
+       return readl(addr + offset);
+}
+EXPORT_SYMBOL_GPL(sst_shim32_read);
+
+void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
+{
+       memcpy_toio(addr + offset, &value, sizeof(value));
+}
+EXPORT_SYMBOL_GPL(sst_shim32_write64);
+
+u64 sst_shim32_read64(void __iomem *addr, u32 offset)
+{
+       u64 val;
+
+       memcpy_fromio(&val, addr + offset, sizeof(val));
+       return val;
+}
+EXPORT_SYMBOL_GPL(sst_shim32_read64);
+
+static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest,
+       u32 *src, size_t bytes)
+{
+       int i, words = bytes >> 2;
+
+       for (i = 0; i < words; i++)
+               writel(src[i], dest + i);
+}
+
+static inline void _sst_memcpy_fromio_32(u32 *dest,
+       const volatile __iomem u32 *src, size_t bytes)
+{
+       int i, words = bytes >> 2;
+
+       for (i = 0; i < words; i++)
+               dest[i] = readl(src + i);
+}
+
+void sst_memcpy_toio_32(struct sst_dsp *sst,
+       void __iomem *dest, void *src, size_t bytes)
+{
+       _sst_memcpy_toio_32(dest, src, bytes);
+}
+EXPORT_SYMBOL_GPL(sst_memcpy_toio_32);
+
+void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest,
+       void __iomem *src, size_t bytes)
+{
+       _sst_memcpy_fromio_32(dest, src, bytes);
+}
+EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32);
+
+/* Public API */
+void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       sst->ops->write(sst->addr.shim, offset, value);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
+
+u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       val = sst->ops->read(sst->addr.shim, offset);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
+
+void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       sst->ops->write64(sst->addr.shim, offset, value);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write64);
+
+u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset)
+{
+       unsigned long flags;
+       u64 val;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       val = sst->ops->read64(sst->addr.shim, offset);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read64);
+
+void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
+{
+       sst->ops->write(sst->addr.shim, offset, value);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
+
+u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
+{
+       return sst->ops->read(sst->addr.shim, offset);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
+
+void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value)
+{
+       sst->ops->write64(sst->addr.shim, offset, value);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked);
+
+u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset)
+{
+       return sst->ops->read64(sst->addr.shim, offset);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked);
+
+int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
+                               u32 mask, u32 value)
+{
+       bool change;
+       unsigned int old, new;
+       u32 ret;
+
+       ret = sst_dsp_shim_read_unlocked(sst, offset);
+
+       old = ret;
+       new = (old & (~mask)) | (value & mask);
+
+       change = (old != new);
+       if (change)
+               sst_dsp_shim_write_unlocked(sst, offset, new);
+
+       return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
+
+int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
+                               u64 mask, u64 value)
+{
+       bool change;
+       u64 old, new;
+
+       old = sst_dsp_shim_read64_unlocked(sst, offset);
+
+       new = (old & (~mask)) | (value & mask);
+
+       change = (old != new);
+       if (change)
+               sst_dsp_shim_write64_unlocked(sst, offset, new);
+
+       return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
+
+int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
+                               u32 mask, u32 value)
+{
+       unsigned long flags;
+       bool change;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+       return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
+
+int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
+                               u64 mask, u64 value)
+{
+       unsigned long flags;
+       bool change;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+       return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
+
+void sst_dsp_dump(struct sst_dsp *sst)
+{
+       if (sst->ops->dump)
+               sst->ops->dump(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dump);
+
+void sst_dsp_reset(struct sst_dsp *sst)
+{
+       if (sst->ops->reset)
+               sst->ops->reset(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_reset);
+
+int sst_dsp_boot(struct sst_dsp *sst)
+{
+       if (sst->ops->boot)
+               sst->ops->boot(sst);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_boot);
+
+int sst_dsp_wake(struct sst_dsp *sst)
+{
+       if (sst->ops->wake)
+               return sst->ops->wake(sst);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_wake);
+
+void sst_dsp_sleep(struct sst_dsp *sst)
+{
+       if (sst->ops->sleep)
+               sst->ops->sleep(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_sleep);
+
+void sst_dsp_stall(struct sst_dsp *sst)
+{
+       if (sst->ops->stall)
+               sst->ops->stall(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_stall);
+
+void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
+{
+       sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
+       trace_sst_ipc_msg_tx(msg);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx);
+
+u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp)
+{
+       u32 msg;
+
+       msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
+       trace_sst_ipc_msg_rx(msg);
+
+       return msg;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx);
+
+int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
+       u32 outbox_offset, size_t outbox_size)
+{
+       sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
+       sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
+       sst->mailbox.in_size = inbox_size;
+       sst->mailbox.out_size = outbox_size;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
+
+void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
+{
+       u32 i;
+
+       trace_sst_ipc_outbox_write(bytes);
+
+       memcpy_toio(sst->mailbox.out_base, message, bytes);
+
+       for (i = 0; i < bytes; i += 4)
+               trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
+
+void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
+{
+       u32 i;
+
+       trace_sst_ipc_outbox_read(bytes);
+
+       memcpy_fromio(message, sst->mailbox.out_base, bytes);
+
+       for (i = 0; i < bytes; i += 4)
+               trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
+
+void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
+{
+       u32 i;
+
+       trace_sst_ipc_inbox_write(bytes);
+
+       memcpy_toio(sst->mailbox.in_base, message, bytes);
+
+       for (i = 0; i < bytes; i += 4)
+               trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
+
+void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
+{
+       u32 i;
+
+       trace_sst_ipc_inbox_read(bytes);
+
+       memcpy_fromio(message, sst->mailbox.in_base, bytes);
+
+       for (i = 0; i < bytes; i += 4)
+               trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
+
+struct sst_dsp *sst_dsp_new(struct device *dev,
+       struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
+{
+       struct sst_dsp *sst;
+       int err;
+
+       dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
+
+       sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
+       if (sst == NULL)
+               return NULL;
+
+       spin_lock_init(&sst->spinlock);
+       mutex_init(&sst->mutex);
+       sst->dev = dev;
+       sst->dma_dev = pdata->dma_dev;
+       sst->thread_context = sst_dev->thread_context;
+       sst->sst_dev = sst_dev;
+       sst->id = pdata->id;
+       sst->irq = pdata->irq;
+       sst->ops = sst_dev->ops;
+       sst->pdata = pdata;
+       INIT_LIST_HEAD(&sst->used_block_list);
+       INIT_LIST_HEAD(&sst->free_block_list);
+       INIT_LIST_HEAD(&sst->module_list);
+       INIT_LIST_HEAD(&sst->fw_list);
+       INIT_LIST_HEAD(&sst->scratch_block_list);
+
+       /* Initialise SST Audio DSP */
+       if (sst->ops->init) {
+               err = sst->ops->init(sst, pdata);
+               if (err < 0)
+                       return NULL;
+       }
+
+       /* Register the ISR */
+       err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
+               sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
+       if (err)
+               goto irq_err;
+
+       err = sst_dma_new(sst);
+       if (err)
+               dev_warn(dev, "sst_dma_new failed %d\n", err);
+
+       return sst;
+
+irq_err:
+       if (sst->ops->free)
+               sst->ops->free(sst);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_new);
+
+void sst_dsp_free(struct sst_dsp *sst)
+{
+       free_irq(sst->irq, sst);
+       if (sst->ops->free)
+               sst->ops->free(sst);
+
+       sst_dma_free(sst->dma);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_free);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("Intel SST Core");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h
new file mode 100644 (file)
index 0000000..96aeb25
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Intel Smart Sound Technology (SST) Core
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SOUND_SOC_SST_DSP_H
+#define __SOUND_SOC_SST_DSP_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+
+/* SST Device IDs  */
+#define SST_DEV_ID_LYNX_POINT          0x33C8
+#define SST_DEV_ID_WILDCAT_POINT       0x3438
+#define SST_DEV_ID_BYT                 0x0F28
+
+/* Supported SST DMA Devices */
+#define SST_DMA_TYPE_DW                1
+
+/* autosuspend delay 5s*/
+#define SST_RUNTIME_SUSPEND_DELAY      (5 * 1000)
+
+/* SST Shim register map
+ * The register naming can differ between products. Some products also
+ * contain extra functionality.
+ */
+#define SST_CSR                        0x00
+#define SST_PISR               0x08
+#define SST_PIMR               0x10
+#define SST_ISRX               0x18
+#define SST_ISRD               0x20
+#define SST_IMRX               0x28
+#define SST_IMRD               0x30
+#define SST_IPCX               0x38 /* IPC IA -> SST */
+#define SST_IPCD               0x40 /* IPC SST -> IA */
+#define SST_ISRSC              0x48
+#define SST_ISRLPESC           0x50
+#define SST_IMRSC              0x58
+#define SST_IMRLPESC           0x60
+#define SST_IPCSC              0x68
+#define SST_IPCLPESC           0x70
+#define SST_CLKCTL             0x78
+#define SST_CSR2               0x80
+#define SST_LTRC               0xE0
+#define SST_HMDC               0xE8
+
+#define SST_SHIM_BEGIN         SST_CSR
+#define SST_SHIM_END           SST_HDMC
+
+#define SST_DBGO               0xF0
+
+#define SST_SHIM_SIZE          0x100
+#define SST_PWMCTRL             0x1000
+
+/* SST Shim Register bits
+ * The register bit naming can differ between products. Some products also
+ * contain extra functionality.
+ */
+
+/* CSR / CS */
+#define SST_CSR_RST            (0x1 << 1)
+#define SST_CSR_SBCS0          (0x1 << 2)
+#define SST_CSR_SBCS1          (0x1 << 3)
+#define SST_CSR_DCS(x)         (x << 4)
+#define SST_CSR_DCS_MASK       (0x7 << 4)
+#define SST_CSR_STALL          (0x1 << 10)
+#define SST_CSR_S0IOCS         (0x1 << 21)
+#define SST_CSR_S1IOCS         (0x1 << 23)
+#define SST_CSR_LPCS           (0x1 << 31)
+#define SST_CSR_24MHZ_LPCS     (SST_CSR_SBCS0 | SST_CSR_SBCS1 | SST_CSR_LPCS)
+#define SST_CSR_24MHZ_NO_LPCS  (SST_CSR_SBCS0 | SST_CSR_SBCS1)
+#define SST_BYT_CSR_RST                (0x1 << 0)
+#define SST_BYT_CSR_VECTOR_SEL (0x1 << 1)
+#define SST_BYT_CSR_STALL      (0x1 << 2)
+#define SST_BYT_CSR_PWAITMODE  (0x1 << 3)
+
+/*  ISRX / ISC */
+#define SST_ISRX_BUSY          (0x1 << 1)
+#define SST_ISRX_DONE          (0x1 << 0)
+#define SST_BYT_ISRX_REQUEST   (0x1 << 1)
+
+/*  ISRD / ISD */
+#define SST_ISRD_BUSY          (0x1 << 1)
+#define SST_ISRD_DONE          (0x1 << 0)
+
+/* IMRX / IMC */
+#define SST_IMRX_BUSY          (0x1 << 1)
+#define SST_IMRX_DONE          (0x1 << 0)
+#define SST_BYT_IMRX_REQUEST   (0x1 << 1)
+
+/* IMRD / IMD */
+#define SST_IMRD_DONE          (0x1 << 0)
+#define SST_IMRD_BUSY          (0x1 << 1)
+#define SST_IMRD_SSP0          (0x1 << 16)
+#define SST_IMRD_DMAC0         (0x1 << 21)
+#define SST_IMRD_DMAC1         (0x1 << 22)
+#define SST_IMRD_DMAC          (SST_IMRD_DMAC0 | SST_IMRD_DMAC1)
+
+/*  IPCX / IPCC */
+#define        SST_IPCX_DONE           (0x1 << 30)
+#define        SST_IPCX_BUSY           (0x1 << 31)
+#define SST_BYT_IPCX_DONE      ((u64)0x1 << 62)
+#define SST_BYT_IPCX_BUSY      ((u64)0x1 << 63)
+
+/*  IPCD */
+#define        SST_IPCD_DONE           (0x1 << 30)
+#define        SST_IPCD_BUSY           (0x1 << 31)
+#define SST_BYT_IPCD_DONE      ((u64)0x1 << 62)
+#define SST_BYT_IPCD_BUSY      ((u64)0x1 << 63)
+
+/* CLKCTL */
+#define SST_CLKCTL_SMOS(x)     (x << 24)
+#define SST_CLKCTL_MASK                (3 << 24)
+#define SST_CLKCTL_DCPLCG      (1 << 18)
+#define SST_CLKCTL_SCOE1       (1 << 17)
+#define SST_CLKCTL_SCOE0       (1 << 16)
+
+/* CSR2 / CS2 */
+#define SST_CSR2_SDFD_SSP0     (1 << 1)
+#define SST_CSR2_SDFD_SSP1     (1 << 2)
+
+/* LTRC */
+#define SST_LTRC_VAL(x)                (x << 0)
+
+/* HMDC */
+#define SST_HMDC_HDDA0(x)      (x << 0)
+#define SST_HMDC_HDDA1(x)      (x << 7)
+#define SST_HMDC_HDDA_E0_CH0   1
+#define SST_HMDC_HDDA_E0_CH1   2
+#define SST_HMDC_HDDA_E0_CH2   4
+#define SST_HMDC_HDDA_E0_CH3   8
+#define SST_HMDC_HDDA_E1_CH0   SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH0)
+#define SST_HMDC_HDDA_E1_CH1   SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH1)
+#define SST_HMDC_HDDA_E1_CH2   SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH2)
+#define SST_HMDC_HDDA_E1_CH3   SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH3)
+#define SST_HMDC_HDDA_E0_ALLCH (SST_HMDC_HDDA_E0_CH0 | SST_HMDC_HDDA_E0_CH1 | \
+                                SST_HMDC_HDDA_E0_CH2 | SST_HMDC_HDDA_E0_CH3)
+#define SST_HMDC_HDDA_E1_ALLCH (SST_HMDC_HDDA_E1_CH0 | SST_HMDC_HDDA_E1_CH1 | \
+                                SST_HMDC_HDDA_E1_CH2 | SST_HMDC_HDDA_E1_CH3)
+
+
+/* SST Vendor Defined Registers and bits */
+#define SST_VDRTCTL0           0xa0
+#define SST_VDRTCTL1           0xa4
+#define SST_VDRTCTL2           0xa8
+#define SST_VDRTCTL3           0xaC
+
+/* VDRTCTL0 */
+#define SST_VDRTCL0_D3PGD              (1 << 0)
+#define SST_VDRTCL0_D3SRAMPGD          (1 << 1)
+#define SST_VDRTCL0_DSRAMPGE_SHIFT     12
+#define SST_VDRTCL0_DSRAMPGE_MASK      (0xfffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
+#define SST_VDRTCL0_ISRAMPGE_SHIFT     2
+#define SST_VDRTCL0_ISRAMPGE_MASK      (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
+
+/* VDRTCTL2 */
+#define SST_VDRTCL2_DCLCGE             (1 << 1)
+#define SST_VDRTCL2_DTCGE              (1 << 10)
+#define SST_VDRTCL2_APLLSE_MASK                (1 << 31)
+
+/* PMCS */
+#define SST_PMCS               0x84
+#define SST_PMCS_PS_MASK       0x3
+
+struct sst_dsp;
+
+/*
+ * SST Device.
+ *
+ * This structure is populated by the SST core driver.
+ */
+struct sst_dsp_device {
+       /* Mandatory fields */
+       struct sst_ops *ops;
+       irqreturn_t (*thread)(int irq, void *context);
+       void *thread_context;
+};
+
+/*
+ * SST Platform Data.
+ */
+struct sst_pdata {
+       /* ACPI data */
+       u32 lpe_base;
+       u32 lpe_size;
+       u32 pcicfg_base;
+       u32 pcicfg_size;
+       u32 fw_base;
+       u32 fw_size;
+       int irq;
+
+       /* Firmware */
+       const struct firmware *fw;
+
+       /* DMA */
+       int resindex_dma_base; /* other fields invalid if equals to -1 */
+       u32 dma_base;
+       u32 dma_size;
+       int dma_engine;
+       struct device *dma_dev;
+
+       /* DSP */
+       u32 id;
+       void *dsp;
+};
+
+/* Initialization */
+struct sst_dsp *sst_dsp_new(struct device *dev,
+       struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
+void sst_dsp_free(struct sst_dsp *sst);
+
+/* SHIM Read / Write */
+void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
+u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
+                               u32 mask, u32 value);
+void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value);
+u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
+                               u64 mask, u64 value);
+
+/* SHIM Read / Write Unlocked for callers already holding sst lock */
+void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
+u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
+                               u32 mask, u32 value);
+void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value);
+u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
+                                       u64 mask, u64 value);
+
+/* Internal generic low-level SST IO functions - can be overidden */
+void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
+u32 sst_shim32_read(void __iomem *addr, u32 offset);
+void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value);
+u64 sst_shim32_read64(void __iomem *addr, u32 offset);
+void sst_memcpy_toio_32(struct sst_dsp *sst,
+                       void __iomem *dest, void *src, size_t bytes);
+void sst_memcpy_fromio_32(struct sst_dsp *sst,
+                         void *dest, void __iomem *src, size_t bytes);
+
+/* DSP reset & boot */
+void sst_dsp_reset(struct sst_dsp *sst);
+int sst_dsp_boot(struct sst_dsp *sst);
+int sst_dsp_wake(struct sst_dsp *sst);
+void sst_dsp_sleep(struct sst_dsp *sst);
+void sst_dsp_stall(struct sst_dsp *sst);
+
+/* DMA */
+int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id);
+void sst_dsp_dma_put_channel(struct sst_dsp *dsp);
+int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr,
+       dma_addr_t src_addr, size_t size);
+int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr,
+       dma_addr_t src_addr, size_t size);
+
+/* Msg IO */
+void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);
+u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp);
+
+/* Mailbox management */
+int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset,
+       size_t inbox_size, u32 outbox_offset, size_t outbox_size);
+void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes);
+
+/* Debug */
+void sst_dsp_dump(struct sst_dsp *sst);
+
+#endif
diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c
new file mode 100644 (file)
index 0000000..ebcca6d
--- /dev/null
@@ -0,0 +1,1205 @@
+/*
+ * Intel SST Firmware Loader
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+
+/* supported DMA engine drivers */
+#include <linux/platform_data/dma-dw.h>
+#include <linux/dma/dw.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+#define SST_DMA_RESOURCES      2
+#define SST_DSP_DMA_MAX_BURST  0x3
+#define SST_HSW_BLOCK_ANY      0xffffffff
+
+#define SST_HSW_MASK_DMA_ADDR_DSP 0xfff00000
+
+struct sst_dma {
+       struct sst_dsp *sst;
+
+       struct dw_dma_chip *chip;
+
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *ch;
+};
+
+static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
+{
+       /* __iowrite32_copy use 32bit size values so divide by 4 */
+       __iowrite32_copy((void *)dest, src, bytes/4);
+}
+
+static void sst_dma_transfer_complete(void *arg)
+{
+       struct sst_dsp *sst = (struct sst_dsp *)arg;
+
+       dev_dbg(sst->dev, "DMA: callback\n");
+}
+
+static int sst_dsp_dma_copy(struct sst_dsp *sst, dma_addr_t dest_addr,
+       dma_addr_t src_addr, size_t size)
+{
+       struct dma_async_tx_descriptor *desc;
+       struct sst_dma *dma = sst->dma;
+
+       if (dma->ch == NULL) {
+               dev_err(sst->dev, "error: no DMA channel\n");
+               return -ENODEV;
+       }
+
+       dev_dbg(sst->dev, "DMA: src: 0x%lx dest 0x%lx size %zu\n",
+               (unsigned long)src_addr, (unsigned long)dest_addr, size);
+
+       desc = dma->ch->device->device_prep_dma_memcpy(dma->ch, dest_addr,
+               src_addr, size, DMA_CTRL_ACK);
+       if (!desc){
+               dev_err(sst->dev, "error: dma prep memcpy failed\n");
+               return -EINVAL;
+       }
+
+       desc->callback = sst_dma_transfer_complete;
+       desc->callback_param = sst;
+
+       desc->tx_submit(desc);
+       dma_wait_for_async_tx(desc);
+
+       return 0;
+}
+
+/* copy to DSP */
+int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr,
+       dma_addr_t src_addr, size_t size)
+{
+       return sst_dsp_dma_copy(sst, dest_addr | SST_HSW_MASK_DMA_ADDR_DSP,
+                       src_addr, size);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dma_copyto);
+
+/* copy from DSP */
+int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr,
+       dma_addr_t src_addr, size_t size)
+{
+       return sst_dsp_dma_copy(sst, dest_addr,
+               src_addr | SST_HSW_MASK_DMA_ADDR_DSP, size);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dma_copyfrom);
+
+/* remove module from memory - callers hold locks */
+static void block_list_remove(struct sst_dsp *dsp,
+       struct list_head *block_list)
+{
+       struct sst_mem_block *block, *tmp;
+       int err;
+
+       /* disable each block  */
+       list_for_each_entry(block, block_list, module_list) {
+
+               if (block->ops && block->ops->disable) {
+                       err = block->ops->disable(block);
+                       if (err < 0)
+                               dev_err(dsp->dev,
+                                       "error: cant disable block %d:%d\n",
+                                       block->type, block->index);
+               }
+       }
+
+       /* mark each block as free */
+       list_for_each_entry_safe(block, tmp, block_list, module_list) {
+               list_del(&block->module_list);
+               list_move(&block->list, &dsp->free_block_list);
+               dev_dbg(dsp->dev, "block freed %d:%d at offset 0x%x\n",
+                       block->type, block->index, block->offset);
+       }
+}
+
+/* prepare the memory block to receive data from host - callers hold locks */
+static int block_list_prepare(struct sst_dsp *dsp,
+       struct list_head *block_list)
+{
+       struct sst_mem_block *block;
+       int ret = 0;
+
+       /* enable each block so that's it'e ready for data */
+       list_for_each_entry(block, block_list, module_list) {
+
+               if (block->ops && block->ops->enable && !block->users) {
+                       ret = block->ops->enable(block);
+                       if (ret < 0) {
+                               dev_err(dsp->dev,
+                                       "error: cant disable block %d:%d\n",
+                                       block->type, block->index);
+                               goto err;
+                       }
+               }
+       }
+       return ret;
+
+err:
+       list_for_each_entry(block, block_list, module_list) {
+               if (block->ops && block->ops->disable)
+                       block->ops->disable(block);
+       }
+       return ret;
+}
+
+static struct dw_dma_platform_data dw_pdata = {
+       .is_private = 1,
+       .chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
+       .chan_priority = CHAN_PRIORITY_ASCENDING,
+};
+
+static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem,
+       int irq)
+{
+       struct dw_dma_chip *chip;
+       int err;
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return ERR_PTR(-ENOMEM);
+
+       chip->irq = irq;
+       chip->regs = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(chip->regs))
+               return ERR_CAST(chip->regs);
+
+       err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
+       if (err)
+               return ERR_PTR(err);
+
+       chip->dev = dev;
+       err = dw_dma_probe(chip, &dw_pdata);
+       if (err)
+               return ERR_PTR(err);
+
+       return chip;
+}
+
+static void dw_remove(struct dw_dma_chip *chip)
+{
+       dw_dma_remove(chip);
+}
+
+static bool dma_chan_filter(struct dma_chan *chan, void *param)
+{
+       struct sst_dsp *dsp = (struct sst_dsp *)param;
+
+       return chan->device->dev == dsp->dma_dev;
+}
+
+int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id)
+{
+       struct sst_dma *dma = dsp->dma;
+       struct dma_slave_config slave;
+       dma_cap_mask_t mask;
+       int ret;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       dma_cap_set(DMA_MEMCPY, mask);
+
+       dma->ch = dma_request_channel(mask, dma_chan_filter, dsp);
+       if (dma->ch == NULL) {
+               dev_err(dsp->dev, "error: DMA request channel failed\n");
+               return -EIO;
+       }
+
+       memset(&slave, 0, sizeof(slave));
+       slave.direction = DMA_MEM_TO_DEV;
+       slave.src_addr_width =
+               slave.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       slave.src_maxburst = slave.dst_maxburst = SST_DSP_DMA_MAX_BURST;
+
+       ret = dmaengine_slave_config(dma->ch, &slave);
+       if (ret) {
+               dev_err(dsp->dev, "error: unable to set DMA slave config %d\n",
+                       ret);
+               dma_release_channel(dma->ch);
+               dma->ch = NULL;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dma_get_channel);
+
+void sst_dsp_dma_put_channel(struct sst_dsp *dsp)
+{
+       struct sst_dma *dma = dsp->dma;
+
+       if (!dma->ch)
+               return;
+
+       dma_release_channel(dma->ch);
+       dma->ch = NULL;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dma_put_channel);
+
+int sst_dma_new(struct sst_dsp *sst)
+{
+       struct sst_pdata *sst_pdata = sst->pdata;
+       struct sst_dma *dma;
+       struct resource mem;
+       const char *dma_dev_name;
+       int ret = 0;
+
+       if (sst->pdata->resindex_dma_base == -1)
+               /* DMA is not used, return and squelsh error messages */
+               return 0;
+
+       /* configure the correct platform data for whatever DMA engine
+       * is attached to the ADSP IP. */
+       switch (sst->pdata->dma_engine) {
+       case SST_DMA_TYPE_DW:
+               dma_dev_name = "dw_dmac";
+               break;
+       default:
+               dev_err(sst->dev, "error: invalid DMA engine %d\n",
+                       sst->pdata->dma_engine);
+               return -EINVAL;
+       }
+
+       dma = devm_kzalloc(sst->dev, sizeof(struct sst_dma), GFP_KERNEL);
+       if (!dma)
+               return -ENOMEM;
+
+       dma->sst = sst;
+
+       memset(&mem, 0, sizeof(mem));
+
+       mem.start = sst->addr.lpe_base + sst_pdata->dma_base;
+       mem.end   = sst->addr.lpe_base + sst_pdata->dma_base + sst_pdata->dma_size - 1;
+       mem.flags = IORESOURCE_MEM;
+
+       /* now register DMA engine device */
+       dma->chip = dw_probe(sst->dma_dev, &mem, sst_pdata->irq);
+       if (IS_ERR(dma->chip)) {
+               dev_err(sst->dev, "error: DMA device register failed\n");
+               ret = PTR_ERR(dma->chip);
+               goto err_dma_dev;
+       }
+
+       sst->dma = dma;
+       sst->fw_use_dma = true;
+       return 0;
+
+err_dma_dev:
+       devm_kfree(sst->dev, dma);
+       return ret;
+}
+EXPORT_SYMBOL(sst_dma_new);
+
+void sst_dma_free(struct sst_dma *dma)
+{
+
+       if (dma == NULL)
+               return;
+
+       if (dma->ch)
+               dma_release_channel(dma->ch);
+
+       if (dma->chip)
+               dw_remove(dma->chip);
+
+}
+EXPORT_SYMBOL(sst_dma_free);
+
+/* create new generic firmware object */
+struct sst_fw *sst_fw_new(struct sst_dsp *dsp, 
+       const struct firmware *fw, void *private)
+{
+       struct sst_fw *sst_fw;
+       int err;
+
+       if (!dsp->ops->parse_fw)
+               return NULL;
+
+       sst_fw = kzalloc(sizeof(*sst_fw), GFP_KERNEL);
+       if (sst_fw == NULL)
+               return NULL;
+
+       sst_fw->dsp = dsp;
+       sst_fw->private = private;
+       sst_fw->size = fw->size;
+
+       /* allocate DMA buffer to store FW data */
+       sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size,
+                               &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
+       if (!sst_fw->dma_buf) {
+               dev_err(dsp->dev, "error: DMA alloc failed\n");
+               kfree(sst_fw);
+               return NULL;
+       }
+
+       /* copy FW data to DMA-able memory */
+       memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size);
+
+       if (dsp->fw_use_dma) {
+               err = sst_dsp_dma_get_channel(dsp, 0);
+               if (err < 0)
+                       goto chan_err;
+       }
+
+       /* call core specific FW paser to load FW data into DSP */
+       err = dsp->ops->parse_fw(sst_fw);
+       if (err < 0) {
+               dev_err(dsp->dev, "error: parse fw failed %d\n", err);
+               goto parse_err;
+       }
+
+       if (dsp->fw_use_dma)
+               sst_dsp_dma_put_channel(dsp);
+
+       mutex_lock(&dsp->mutex);
+       list_add(&sst_fw->list, &dsp->fw_list);
+       mutex_unlock(&dsp->mutex);
+
+       return sst_fw;
+
+parse_err:
+       if (dsp->fw_use_dma)
+               sst_dsp_dma_put_channel(dsp);
+chan_err:
+       dma_free_coherent(dsp->dma_dev, sst_fw->size,
+                               sst_fw->dma_buf,
+                               sst_fw->dmable_fw_paddr);
+       sst_fw->dma_buf = NULL;
+       kfree(sst_fw);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_fw_new);
+
+int sst_fw_reload(struct sst_fw *sst_fw)
+{
+       struct sst_dsp *dsp = sst_fw->dsp;
+       int ret;
+
+       dev_dbg(dsp->dev, "reloading firmware\n");
+
+       /* call core specific FW paser to load FW data into DSP */
+       ret = dsp->ops->parse_fw(sst_fw);
+       if (ret < 0)
+               dev_err(dsp->dev, "error: parse fw failed %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_fw_reload);
+
+void sst_fw_unload(struct sst_fw *sst_fw)
+{
+       struct sst_dsp *dsp = sst_fw->dsp;
+       struct sst_module *module, *mtmp;
+       struct sst_module_runtime *runtime, *rtmp;
+
+       dev_dbg(dsp->dev, "unloading firmware\n");
+
+       mutex_lock(&dsp->mutex);
+
+       /* check module by module */
+       list_for_each_entry_safe(module, mtmp, &dsp->module_list, list) {
+               if (module->sst_fw == sst_fw) {
+
+                       /* remove runtime modules */
+                       list_for_each_entry_safe(runtime, rtmp, &module->runtime_list, list) {
+
+                               block_list_remove(dsp, &runtime->block_list);
+                               list_del(&runtime->list);
+                               kfree(runtime);
+                       }
+
+                       /* now remove the module */
+                       block_list_remove(dsp, &module->block_list);
+                       list_del(&module->list);
+                       kfree(module);
+               }
+       }
+
+       /* remove all scratch blocks */
+       block_list_remove(dsp, &dsp->scratch_block_list);
+
+       mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_fw_unload);
+
+/* free single firmware object */
+void sst_fw_free(struct sst_fw *sst_fw)
+{
+       struct sst_dsp *dsp = sst_fw->dsp;
+
+       mutex_lock(&dsp->mutex);
+       list_del(&sst_fw->list);
+       mutex_unlock(&dsp->mutex);
+
+       if (sst_fw->dma_buf)
+               dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,
+                       sst_fw->dmable_fw_paddr);
+       kfree(sst_fw);
+}
+EXPORT_SYMBOL_GPL(sst_fw_free);
+
+/* free all firmware objects */
+void sst_fw_free_all(struct sst_dsp *dsp)
+{
+       struct sst_fw *sst_fw, *t;
+
+       mutex_lock(&dsp->mutex);
+       list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
+
+               list_del(&sst_fw->list);
+               dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
+                       sst_fw->dmable_fw_paddr);
+               kfree(sst_fw);
+       }
+       mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_fw_free_all);
+
+/* create a new SST generic module from FW template */
+struct sst_module *sst_module_new(struct sst_fw *sst_fw,
+       struct sst_module_template *template, void *private)
+{
+       struct sst_dsp *dsp = sst_fw->dsp;
+       struct sst_module *sst_module;
+
+       sst_module = kzalloc(sizeof(*sst_module), GFP_KERNEL);
+       if (sst_module == NULL)
+               return NULL;
+
+       sst_module->id = template->id;
+       sst_module->dsp = dsp;
+       sst_module->sst_fw = sst_fw;
+       sst_module->scratch_size = template->scratch_size;
+       sst_module->persistent_size = template->persistent_size;
+       sst_module->entry = template->entry;
+       sst_module->state = SST_MODULE_STATE_UNLOADED;
+
+       INIT_LIST_HEAD(&sst_module->block_list);
+       INIT_LIST_HEAD(&sst_module->runtime_list);
+
+       mutex_lock(&dsp->mutex);
+       list_add(&sst_module->list, &dsp->module_list);
+       mutex_unlock(&dsp->mutex);
+
+       return sst_module;
+}
+EXPORT_SYMBOL_GPL(sst_module_new);
+
+/* free firmware module and remove from available list */
+void sst_module_free(struct sst_module *sst_module)
+{
+       struct sst_dsp *dsp = sst_module->dsp;
+
+       mutex_lock(&dsp->mutex);
+       list_del(&sst_module->list);
+       mutex_unlock(&dsp->mutex);
+
+       kfree(sst_module);
+}
+EXPORT_SYMBOL_GPL(sst_module_free);
+
+struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module,
+       int id, void *private)
+{
+       struct sst_dsp *dsp = module->dsp;
+       struct sst_module_runtime *runtime;
+
+       runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
+       if (runtime == NULL)
+               return NULL;
+
+       runtime->id = id;
+       runtime->dsp = dsp;
+       runtime->module = module;
+       INIT_LIST_HEAD(&runtime->block_list);
+
+       mutex_lock(&dsp->mutex);
+       list_add(&runtime->list, &module->runtime_list);
+       mutex_unlock(&dsp->mutex);
+
+       return runtime;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_new);
+
+void sst_module_runtime_free(struct sst_module_runtime *runtime)
+{
+       struct sst_dsp *dsp = runtime->dsp;
+
+       mutex_lock(&dsp->mutex);
+       list_del(&runtime->list);
+       mutex_unlock(&dsp->mutex);
+
+       kfree(runtime);
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_free);
+
+static struct sst_mem_block *find_block(struct sst_dsp *dsp,
+       struct sst_block_allocator *ba)
+{
+       struct sst_mem_block *block;
+
+       list_for_each_entry(block, &dsp->free_block_list, list) {
+               if (block->type == ba->type && block->offset == ba->offset)
+                       return block;
+       }
+
+       return NULL;
+}
+
+/* Block allocator must be on block boundary */
+static int block_alloc_contiguous(struct sst_dsp *dsp,
+       struct sst_block_allocator *ba, struct list_head *block_list)
+{
+       struct list_head tmp = LIST_HEAD_INIT(tmp);
+       struct sst_mem_block *block;
+       u32 block_start = SST_HSW_BLOCK_ANY;
+       int size = ba->size, offset = ba->offset;
+
+       while (ba->size > 0) {
+
+               block = find_block(dsp, ba);
+               if (!block) {
+                       list_splice(&tmp, &dsp->free_block_list);
+
+                       ba->size = size;
+                       ba->offset = offset;
+                       return -ENOMEM;
+               }
+
+               list_move_tail(&block->list, &tmp);
+               ba->offset += block->size;
+               ba->size -= block->size;
+       }
+       ba->size = size;
+       ba->offset = offset;
+
+       list_for_each_entry(block, &tmp, list) {
+
+               if (block->offset < block_start)
+                       block_start = block->offset;
+
+               list_add(&block->module_list, block_list);
+
+               dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
+                       block->type, block->index, block->offset);
+       }
+
+       list_splice(&tmp, &dsp->used_block_list);
+       return 0;
+}
+
+/* allocate first free DSP blocks for data - callers hold locks */
+static int block_alloc(struct sst_dsp *dsp, struct sst_block_allocator *ba,
+       struct list_head *block_list)
+{
+       struct sst_mem_block *block, *tmp;
+       int ret = 0;
+
+       if (ba->size == 0)
+               return 0;
+
+       /* find first free whole blocks that can hold module */
+       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+
+               /* ignore blocks with wrong type */
+               if (block->type != ba->type)
+                       continue;
+
+               if (ba->size > block->size)
+                       continue;
+
+               ba->offset = block->offset;
+               block->bytes_used = ba->size % block->size;
+               list_add(&block->module_list, block_list);
+               list_move(&block->list, &dsp->used_block_list);
+               dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
+                       block->type, block->index, block->offset);
+               return 0;
+       }
+
+       /* then find free multiple blocks that can hold module */
+       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+
+               /* ignore blocks with wrong type */
+               if (block->type != ba->type)
+                       continue;
+
+               /* do we span > 1 blocks */
+               if (ba->size > block->size) {
+
+                       /* align ba to block boundary */
+                       ba->offset = block->offset;
+
+                       ret = block_alloc_contiguous(dsp, ba, block_list);
+                       if (ret == 0)
+                               return ret;
+
+               }
+       }
+
+       /* not enough free block space */
+       return -ENOMEM;
+}
+
+int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba,
+       struct list_head *block_list)
+{
+       int ret;
+
+       dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n",
+               ba->size, ba->offset, ba->type);
+
+       mutex_lock(&dsp->mutex);
+
+       ret = block_alloc(dsp, ba, block_list);
+       if (ret < 0) {
+               dev_err(dsp->dev, "error: can't alloc blocks %d\n", ret);
+               goto out;
+       }
+
+       /* prepare DSP blocks for module usage */
+       ret = block_list_prepare(dsp, block_list);
+       if (ret < 0)
+               dev_err(dsp->dev, "error: prepare failed\n");
+
+out:
+       mutex_unlock(&dsp->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_alloc_blocks);
+
+int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list)
+{
+       mutex_lock(&dsp->mutex);
+       block_list_remove(dsp, block_list);
+       mutex_unlock(&dsp->mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_free_blocks);
+
+/* allocate memory blocks for static module addresses - callers hold locks */
+static int block_alloc_fixed(struct sst_dsp *dsp, struct sst_block_allocator *ba,
+       struct list_head *block_list)
+{
+       struct sst_mem_block *block, *tmp;
+       struct sst_block_allocator ba_tmp = *ba;
+       u32 end = ba->offset + ba->size, block_end;
+       int err;
+
+       /* only IRAM/DRAM blocks are managed */
+       if (ba->type != SST_MEM_IRAM && ba->type != SST_MEM_DRAM)
+               return 0;
+
+       /* are blocks already attached to this module */
+       list_for_each_entry_safe(block, tmp, block_list, module_list) {
+
+               /* ignore blocks with wrong type */
+               if (block->type != ba->type)
+                       continue;
+
+               block_end = block->offset + block->size;
+
+               /* find block that holds section */
+               if (ba->offset >= block->offset && end <= block_end)
+                       return 0;
+
+               /* does block span more than 1 section */
+               if (ba->offset >= block->offset && ba->offset < block_end) {
+
+                       /* align ba to block boundary */
+                       ba_tmp.size -= block_end - ba->offset;
+                       ba_tmp.offset = block_end;
+                       err = block_alloc_contiguous(dsp, &ba_tmp, block_list);
+                       if (err < 0)
+                               return -ENOMEM;
+
+                       /* module already owns blocks */
+                       return 0;
+               }
+       }
+
+       /* find first free blocks that can hold section in free list */
+       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+               block_end = block->offset + block->size;
+
+               /* ignore blocks with wrong type */
+               if (block->type != ba->type)
+                       continue;
+
+               /* find block that holds section */
+               if (ba->offset >= block->offset && end <= block_end) {
+
+                       /* add block */
+                       list_move(&block->list, &dsp->used_block_list);
+                       list_add(&block->module_list, block_list);
+                       dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
+                               block->type, block->index, block->offset);
+                       return 0;
+               }
+
+               /* does block span more than 1 section */
+               if (ba->offset >= block->offset && ba->offset < block_end) {
+
+                       /* add block */
+                       list_move(&block->list, &dsp->used_block_list);
+                       list_add(&block->module_list, block_list);
+                       /* align ba to block boundary */
+                       ba_tmp.size -= block_end - ba->offset;
+                       ba_tmp.offset = block_end;
+
+                       err = block_alloc_contiguous(dsp, &ba_tmp, block_list);
+                       if (err < 0)
+                               return -ENOMEM;
+
+                       return 0;
+               }
+       }
+
+       return -ENOMEM;
+}
+
+/* Load fixed module data into DSP memory blocks */
+int sst_module_alloc_blocks(struct sst_module *module)
+{
+       struct sst_dsp *dsp = module->dsp;
+       struct sst_fw *sst_fw = module->sst_fw;
+       struct sst_block_allocator ba;
+       int ret;
+
+       memset(&ba, 0, sizeof(ba));
+       ba.size = module->size;
+       ba.type = module->type;
+       ba.offset = module->offset;
+
+       dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n",
+               ba.size, ba.offset, ba.type);
+
+       mutex_lock(&dsp->mutex);
+
+       /* alloc blocks that includes this section */
+       ret = block_alloc_fixed(dsp, &ba, &module->block_list);
+       if (ret < 0) {
+               dev_err(dsp->dev,
+                       "error: no free blocks for section at offset 0x%x size 0x%x\n",
+                       module->offset, module->size);
+               mutex_unlock(&dsp->mutex);
+               return -ENOMEM;
+       }
+
+       /* prepare DSP blocks for module copy */
+       ret = block_list_prepare(dsp, &module->block_list);
+       if (ret < 0) {
+               dev_err(dsp->dev, "error: fw module prepare failed\n");
+               goto err;
+       }
+
+       /* copy partial module data to blocks */
+       if (dsp->fw_use_dma) {
+               ret = sst_dsp_dma_copyto(dsp,
+                       dsp->addr.lpe_base + module->offset,
+                       sst_fw->dmable_fw_paddr + module->data_offset,
+                       module->size);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "error: module copy failed\n");
+                       goto err;
+               }
+       } else
+               sst_memcpy32(dsp->addr.lpe + module->offset, module->data,
+                       module->size);
+
+       mutex_unlock(&dsp->mutex);
+       return ret;
+
+err:
+       block_list_remove(dsp, &module->block_list);
+       mutex_unlock(&dsp->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_alloc_blocks);
+
+/* Unload entire module from DSP memory */
+int sst_module_free_blocks(struct sst_module *module)
+{
+       struct sst_dsp *dsp = module->dsp;
+
+       mutex_lock(&dsp->mutex);
+       block_list_remove(dsp, &module->block_list);
+       mutex_unlock(&dsp->mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_module_free_blocks);
+
+int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
+       int offset)
+{
+       struct sst_dsp *dsp = runtime->dsp;
+       struct sst_module *module = runtime->module;
+       struct sst_block_allocator ba;
+       int ret;
+
+       if (module->persistent_size == 0)
+               return 0;
+
+       memset(&ba, 0, sizeof(ba));
+       ba.size = module->persistent_size;
+       ba.type = SST_MEM_DRAM;
+
+       mutex_lock(&dsp->mutex);
+
+       /* do we need to allocate at a fixed address ? */
+       if (offset != 0) {
+
+               ba.offset = offset;
+
+               dev_dbg(dsp->dev, "persistent fixed block request 0x%x bytes type %d offset 0x%x\n",
+                       ba.size, ba.type, ba.offset);
+
+               /* alloc blocks that includes this section */
+               ret = block_alloc_fixed(dsp, &ba, &runtime->block_list);
+
+       } else {
+               dev_dbg(dsp->dev, "persistent block request 0x%x bytes type %d\n",
+                       ba.size, ba.type);
+
+               /* alloc blocks that includes this section */
+               ret = block_alloc(dsp, &ba, &runtime->block_list);
+       }
+       if (ret < 0) {
+               dev_err(dsp->dev,
+               "error: no free blocks for runtime module size 0x%x\n",
+                       module->persistent_size);
+               mutex_unlock(&dsp->mutex);
+               return -ENOMEM;
+       }
+       runtime->persistent_offset = ba.offset;
+
+       /* prepare DSP blocks for module copy */
+       ret = block_list_prepare(dsp, &runtime->block_list);
+       if (ret < 0) {
+               dev_err(dsp->dev, "error: runtime block prepare failed\n");
+               goto err;
+       }
+
+       mutex_unlock(&dsp->mutex);
+       return ret;
+
+err:
+       block_list_remove(dsp, &module->block_list);
+       mutex_unlock(&dsp->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_alloc_blocks);
+
+int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime)
+{
+       struct sst_dsp *dsp = runtime->dsp;
+
+       mutex_lock(&dsp->mutex);
+       block_list_remove(dsp, &runtime->block_list);
+       mutex_unlock(&dsp->mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_free_blocks);
+
+int sst_module_runtime_save(struct sst_module_runtime *runtime,
+       struct sst_module_runtime_context *context)
+{
+       struct sst_dsp *dsp = runtime->dsp;
+       struct sst_module *module = runtime->module;
+       int ret = 0;
+
+       dev_dbg(dsp->dev, "saving runtime %d memory at 0x%x size 0x%x\n",
+               runtime->id, runtime->persistent_offset,
+               module->persistent_size);
+
+       context->buffer = dma_alloc_coherent(dsp->dma_dev,
+               module->persistent_size,
+               &context->dma_buffer, GFP_DMA | GFP_KERNEL);
+       if (!context->buffer) {
+               dev_err(dsp->dev, "error: DMA context alloc failed\n");
+               return -ENOMEM;
+       }
+
+       mutex_lock(&dsp->mutex);
+
+       if (dsp->fw_use_dma) {
+
+               ret = sst_dsp_dma_get_channel(dsp, 0);
+               if (ret < 0)
+                       goto err;
+
+               ret = sst_dsp_dma_copyfrom(dsp, context->dma_buffer,
+                       dsp->addr.lpe_base + runtime->persistent_offset,
+                       module->persistent_size);
+               sst_dsp_dma_put_channel(dsp);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "error: context copy failed\n");
+                       goto err;
+               }
+       } else
+               sst_memcpy32(context->buffer, dsp->addr.lpe +
+                       runtime->persistent_offset,
+                       module->persistent_size);
+
+err:
+       mutex_unlock(&dsp->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_save);
+
+int sst_module_runtime_restore(struct sst_module_runtime *runtime,
+       struct sst_module_runtime_context *context)
+{
+       struct sst_dsp *dsp = runtime->dsp;
+       struct sst_module *module = runtime->module;
+       int ret = 0;
+
+       dev_dbg(dsp->dev, "restoring runtime %d memory at 0x%x size 0x%x\n",
+               runtime->id, runtime->persistent_offset,
+               module->persistent_size);
+
+       mutex_lock(&dsp->mutex);
+
+       if (!context->buffer) {
+               dev_info(dsp->dev, "no context buffer need to restore!\n");
+               goto err;
+       }
+
+       if (dsp->fw_use_dma) {
+
+               ret = sst_dsp_dma_get_channel(dsp, 0);
+               if (ret < 0)
+                       goto err;
+
+               ret = sst_dsp_dma_copyto(dsp,
+                       dsp->addr.lpe_base + runtime->persistent_offset,
+                       context->dma_buffer, module->persistent_size);
+               sst_dsp_dma_put_channel(dsp);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "error: module copy failed\n");
+                       goto err;
+               }
+       } else
+               sst_memcpy32(dsp->addr.lpe + runtime->persistent_offset,
+                       context->buffer, module->persistent_size);
+
+       dma_free_coherent(dsp->dma_dev, module->persistent_size,
+                               context->buffer, context->dma_buffer);
+       context->buffer = NULL;
+
+err:
+       mutex_unlock(&dsp->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_restore);
+
+/* register a DSP memory block for use with FW based modules */
+struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
+       u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
+       void *private)
+{
+       struct sst_mem_block *block;
+
+       block = kzalloc(sizeof(*block), GFP_KERNEL);
+       if (block == NULL)
+               return NULL;
+
+       block->offset = offset;
+       block->size = size;
+       block->index = index;
+       block->type = type;
+       block->dsp = dsp;
+       block->private = private;
+       block->ops = ops;
+
+       mutex_lock(&dsp->mutex);
+       list_add(&block->list, &dsp->free_block_list);
+       mutex_unlock(&dsp->mutex);
+
+       return block;
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_register);
+
+/* unregister all DSP memory blocks */
+void sst_mem_block_unregister_all(struct sst_dsp *dsp)
+{
+       struct sst_mem_block *block, *tmp;
+
+       mutex_lock(&dsp->mutex);
+
+       /* unregister used blocks */
+       list_for_each_entry_safe(block, tmp, &dsp->used_block_list, list) {
+               list_del(&block->list);
+               kfree(block);
+       }
+
+       /* unregister free blocks */
+       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+               list_del(&block->list);
+               kfree(block);
+       }
+
+       mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all);
+
+/* allocate scratch buffer blocks */
+int sst_block_alloc_scratch(struct sst_dsp *dsp)
+{
+       struct sst_module *module;
+       struct sst_block_allocator ba;
+       int ret;
+
+       mutex_lock(&dsp->mutex);
+
+       /* calculate required scratch size */
+       dsp->scratch_size = 0;
+       list_for_each_entry(module, &dsp->module_list, list) {
+               dev_dbg(dsp->dev, "module %d scratch req 0x%x bytes\n",
+                       module->id, module->scratch_size);
+               if (dsp->scratch_size < module->scratch_size)
+                       dsp->scratch_size = module->scratch_size;
+       }
+
+       dev_dbg(dsp->dev, "scratch buffer required is 0x%x bytes\n",
+               dsp->scratch_size);
+
+       if (dsp->scratch_size == 0) {
+               dev_info(dsp->dev, "no modules need scratch buffer\n");
+               mutex_unlock(&dsp->mutex);
+               return 0;
+       }
+
+       /* allocate blocks for module scratch buffers */
+       dev_dbg(dsp->dev, "allocating scratch blocks\n");
+
+       ba.size = dsp->scratch_size;
+       ba.type = SST_MEM_DRAM;
+
+       /* do we need to allocate at fixed offset */
+       if (dsp->scratch_offset != 0) {
+
+               dev_dbg(dsp->dev, "block request 0x%x bytes type %d at 0x%x\n",
+                       ba.size, ba.type, ba.offset);
+
+               ba.offset = dsp->scratch_offset;
+
+               /* alloc blocks that includes this section */
+               ret = block_alloc_fixed(dsp, &ba, &dsp->scratch_block_list);
+
+       } else {
+               dev_dbg(dsp->dev, "block request 0x%x bytes type %d\n",
+                       ba.size, ba.type);
+
+               ba.offset = 0;
+               ret = block_alloc(dsp, &ba, &dsp->scratch_block_list);
+       }
+       if (ret < 0) {
+               dev_err(dsp->dev, "error: can't alloc scratch blocks\n");
+               mutex_unlock(&dsp->mutex);
+               return ret;
+       }
+
+       ret = block_list_prepare(dsp, &dsp->scratch_block_list);
+       if (ret < 0) {
+               dev_err(dsp->dev, "error: scratch block prepare failed\n");
+               mutex_unlock(&dsp->mutex);
+               return ret;
+       }
+
+       /* assign the same offset of scratch to each module */
+       dsp->scratch_offset = ba.offset;
+       mutex_unlock(&dsp->mutex);
+       return dsp->scratch_size;
+}
+EXPORT_SYMBOL_GPL(sst_block_alloc_scratch);
+
+/* free all scratch blocks */
+void sst_block_free_scratch(struct sst_dsp *dsp)
+{
+       mutex_lock(&dsp->mutex);
+       block_list_remove(dsp, &dsp->scratch_block_list);
+       mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_block_free_scratch);
+
+/* get a module from it's unique ID */
+struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id)
+{
+       struct sst_module *module;
+
+       mutex_lock(&dsp->mutex);
+
+       list_for_each_entry(module, &dsp->module_list, list) {
+               if (module->id == id) {
+                       mutex_unlock(&dsp->mutex);
+                       return module;
+               }
+       }
+
+       mutex_unlock(&dsp->mutex);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_module_get_from_id);
+
+struct sst_module_runtime *sst_module_runtime_get_from_id(
+       struct sst_module *module, u32 id)
+{
+       struct sst_module_runtime *runtime;
+       struct sst_dsp *dsp = module->dsp;
+
+       mutex_lock(&dsp->mutex);
+
+       list_for_each_entry(runtime, &module->runtime_list, list) {
+               if (runtime->id == id) {
+                       mutex_unlock(&dsp->mutex);
+                       return runtime;
+               }
+       }
+
+       mutex_unlock(&dsp->mutex);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_get_from_id);
+
+/* returns block address in DSP address space */
+u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
+       enum sst_mem_type type)
+{
+       switch (type) {
+       case SST_MEM_IRAM:
+               return offset - dsp->addr.iram_offset +
+                       dsp->addr.dsp_iram_offset;
+       case SST_MEM_DRAM:
+               return offset - dsp->addr.dram_offset +
+                       dsp->addr.dsp_dram_offset;
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(sst_dsp_get_offset);
diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c
new file mode 100644 (file)
index 0000000..4b62a55
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Intel SST generic IPC Support
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <sound/asound.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+#include "sst-ipc.h"
+
+/* IPC message timeout (msecs) */
+#define IPC_TIMEOUT_MSECS      300
+
+#define IPC_EMPTY_LIST_SIZE    8
+
+/* locks held by caller */
+static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc)
+{
+       struct ipc_message *msg = NULL;
+
+       if (!list_empty(&ipc->empty_list)) {
+               msg = list_first_entry(&ipc->empty_list, struct ipc_message,
+                       list);
+               list_del(&msg->list);
+       }
+
+       return msg;
+}
+
+static int tx_wait_done(struct sst_generic_ipc *ipc,
+       struct ipc_message *msg, void *rx_data)
+{
+       unsigned long flags;
+       int ret;
+
+       /* wait for DSP completion (in all cases atm inc pending) */
+       ret = wait_event_timeout(msg->waitq, msg->complete,
+               msecs_to_jiffies(IPC_TIMEOUT_MSECS));
+
+       spin_lock_irqsave(&ipc->dsp->spinlock, flags);
+       if (ret == 0) {
+               if (ipc->ops.shim_dbg != NULL)
+                       ipc->ops.shim_dbg(ipc, "message timeout");
+
+               list_del(&msg->list);
+               ret = -ETIMEDOUT;
+       } else {
+
+               /* copy the data returned from DSP */
+               if (msg->rx_size)
+                       memcpy(rx_data, msg->rx_data, msg->rx_size);
+               ret = msg->errno;
+       }
+
+       list_add_tail(&msg->list, &ipc->empty_list);
+       spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+       return ret;
+}
+
+static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header,
+       void *tx_data, size_t tx_bytes, void *rx_data,
+       size_t rx_bytes, int wait)
+{
+       struct ipc_message *msg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ipc->dsp->spinlock, flags);
+
+       msg = msg_get_empty(ipc);
+       if (msg == NULL) {
+               spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+               return -EBUSY;
+       }
+
+       msg->header = header;
+       msg->tx_size = tx_bytes;
+       msg->rx_size = rx_bytes;
+       msg->wait = wait;
+       msg->errno = 0;
+       msg->pending = false;
+       msg->complete = false;
+
+       if ((tx_bytes) && (ipc->ops.tx_data_copy != NULL))
+               ipc->ops.tx_data_copy(msg, tx_data, tx_bytes);
+
+       list_add_tail(&msg->list, &ipc->tx_list);
+       spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+
+       queue_kthread_work(&ipc->kworker, &ipc->kwork);
+
+       if (wait)
+               return tx_wait_done(ipc, msg, rx_data);
+       else
+               return 0;
+}
+
+static int msg_empty_list_init(struct sst_generic_ipc *ipc)
+{
+       int i;
+
+       ipc->msg = kzalloc(sizeof(struct ipc_message) *
+               IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
+       if (ipc->msg == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+               init_waitqueue_head(&ipc->msg[i].waitq);
+               list_add(&ipc->msg[i].list, &ipc->empty_list);
+       }
+
+       return 0;
+}
+
+static void ipc_tx_msgs(struct kthread_work *work)
+{
+       struct sst_generic_ipc *ipc =
+               container_of(work, struct sst_generic_ipc, kwork);
+       struct ipc_message *msg;
+       unsigned long flags;
+       u64 ipcx;
+
+       spin_lock_irqsave(&ipc->dsp->spinlock, flags);
+
+       if (list_empty(&ipc->tx_list) || ipc->pending) {
+               spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+               return;
+       }
+
+       /* if the DSP is busy, we will TX messages after IRQ.
+        * also postpone if we are in the middle of procesing completion irq*/
+       ipcx = sst_dsp_shim_read_unlocked(ipc->dsp, SST_IPCX);
+       if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) {
+               spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+               return;
+       }
+
+       msg = list_first_entry(&ipc->tx_list, struct ipc_message, list);
+       list_move(&msg->list, &ipc->rx_list);
+
+       if (ipc->ops.tx_msg != NULL)
+               ipc->ops.tx_msg(ipc, msg);
+
+       spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+}
+
+int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
+       void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
+{
+       return ipc_tx_message(ipc, header, tx_data, tx_bytes,
+               rx_data, rx_bytes, 1);
+}
+EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait);
+
+int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,
+       void *tx_data, size_t tx_bytes)
+{
+       return ipc_tx_message(ipc, header, tx_data, tx_bytes,
+               NULL, 0, 0);
+}
+EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait);
+
+struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
+       u64 header)
+{
+       struct ipc_message *msg;
+       u64 mask;
+
+       if (ipc->ops.reply_msg_match != NULL)
+               header = ipc->ops.reply_msg_match(header, &mask);
+
+       if (list_empty(&ipc->rx_list)) {
+               dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n",
+                       header);
+               return NULL;
+       }
+
+       list_for_each_entry(msg, &ipc->rx_list, list) {
+               if ((msg->header & mask) == header)
+                       return msg;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_ipc_reply_find_msg);
+
+/* locks held by caller */
+void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc,
+       struct ipc_message *msg)
+{
+       msg->complete = true;
+
+       if (!msg->wait)
+               list_add_tail(&msg->list, &ipc->empty_list);
+       else
+               wake_up(&msg->waitq);
+}
+EXPORT_SYMBOL_GPL(sst_ipc_tx_msg_reply_complete);
+
+void sst_ipc_drop_all(struct sst_generic_ipc *ipc)
+{
+       struct ipc_message *msg, *tmp;
+       unsigned long flags;
+       int tx_drop_cnt = 0, rx_drop_cnt = 0;
+
+       /* drop all TX and Rx messages before we stall + reset DSP */
+       spin_lock_irqsave(&ipc->dsp->spinlock, flags);
+
+       list_for_each_entry_safe(msg, tmp, &ipc->tx_list, list) {
+               list_move(&msg->list, &ipc->empty_list);
+               tx_drop_cnt++;
+       }
+
+       list_for_each_entry_safe(msg, tmp, &ipc->rx_list, list) {
+               list_move(&msg->list, &ipc->empty_list);
+               rx_drop_cnt++;
+       }
+
+       spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+
+       if (tx_drop_cnt || rx_drop_cnt)
+               dev_err(ipc->dev, "dropped IPC msg RX=%d, TX=%d\n",
+                       tx_drop_cnt, rx_drop_cnt);
+}
+EXPORT_SYMBOL_GPL(sst_ipc_drop_all);
+
+int sst_ipc_init(struct sst_generic_ipc *ipc)
+{
+       int ret;
+
+       INIT_LIST_HEAD(&ipc->tx_list);
+       INIT_LIST_HEAD(&ipc->rx_list);
+       INIT_LIST_HEAD(&ipc->empty_list);
+       init_waitqueue_head(&ipc->wait_txq);
+
+       ret = msg_empty_list_init(ipc);
+       if (ret < 0)
+               return -ENOMEM;
+
+       /* start the IPC message thread */
+       init_kthread_worker(&ipc->kworker);
+       ipc->tx_thread = kthread_run(kthread_worker_fn,
+                                       &ipc->kworker, "%s",
+                                       dev_name(ipc->dev));
+       if (IS_ERR(ipc->tx_thread)) {
+               dev_err(ipc->dev, "error: failed to create message TX task\n");
+               ret = PTR_ERR(ipc->tx_thread);
+               kfree(ipc->msg);
+               return ret;
+       }
+
+       init_kthread_work(&ipc->kwork, ipc_tx_msgs);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_ipc_init);
+
+void sst_ipc_fini(struct sst_generic_ipc *ipc)
+{
+       if (ipc->tx_thread)
+               kthread_stop(ipc->tx_thread);
+
+       if (ipc->msg)
+               kfree(ipc->msg);
+}
+EXPORT_SYMBOL_GPL(sst_ipc_fini);
+
+/* Module information */
+MODULE_AUTHOR("Jin Yao");
+MODULE_DESCRIPTION("Intel SST IPC generic");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h
new file mode 100644 (file)
index 0000000..125ea45
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Intel SST generic IPC Support
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SST_GENERIC_IPC_H
+#define __SST_GENERIC_IPC_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+
+#define IPC_MAX_MAILBOX_BYTES  256
+
+struct ipc_message {
+       struct list_head list;
+       u64 header;
+
+       /* direction wrt host CPU */
+       char tx_data[IPC_MAX_MAILBOX_BYTES];
+       size_t tx_size;
+       char rx_data[IPC_MAX_MAILBOX_BYTES];
+       size_t rx_size;
+
+       wait_queue_head_t waitq;
+       bool pending;
+       bool complete;
+       bool wait;
+       int errno;
+};
+
+struct sst_generic_ipc;
+
+struct sst_plat_ipc_ops {
+       void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *);
+       void (*shim_dbg)(struct sst_generic_ipc *, const char *);
+       void (*tx_data_copy)(struct ipc_message *, char *, size_t);
+       u64  (*reply_msg_match)(u64 header, u64 *mask);
+};
+
+/* SST generic IPC data */
+struct sst_generic_ipc {
+       struct device *dev;
+       struct sst_dsp *dsp;
+
+       /* IPC messaging */
+       struct list_head tx_list;
+       struct list_head rx_list;
+       struct list_head empty_list;
+       wait_queue_head_t wait_txq;
+       struct task_struct *tx_thread;
+       struct kthread_worker kworker;
+       struct kthread_work kwork;
+       bool pending;
+       struct ipc_message *msg;
+
+       struct sst_plat_ipc_ops ops;
+};
+
+int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
+       void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes);
+
+int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,
+       void *tx_data, size_t tx_bytes);
+
+struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
+       u64 header);
+
+void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc,
+       struct ipc_message *msg);
+
+void sst_ipc_drop_all(struct sst_generic_ipc *ipc);
+int sst_ipc_init(struct sst_generic_ipc *ipc);
+void sst_ipc_fini(struct sst_generic_ipc *ipc);
+
+#endif
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c
deleted file mode 100644 (file)
index 35edf51..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Intel Haswell Lynxpoint SST Audio
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-
-#include "sst-dsp.h"
-#include "sst-haswell-ipc.h"
-
-#include "../codecs/rt5640.h"
-
-/* Haswell ULT platforms have a Headphone and Mic jack */
-static const struct snd_soc_dapm_widget haswell_widgets[] = {
-       SND_SOC_DAPM_HP("Headphones", NULL),
-       SND_SOC_DAPM_MIC("Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
-
-       {"Headphones", NULL, "HPOR"},
-       {"Headphones", NULL, "HPOL"},
-       {"IN2P", NULL, "Mic"},
-
-       /* CODEC BE connections */
-       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
-       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
-};
-
-static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
-                       struct snd_pcm_hw_params *params)
-{
-       struct snd_interval *rate = hw_param_interval(params,
-                       SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS);
-
-       /* The ADSP will covert the FE rate to 48k, stereo */
-       rate->min = rate->max = 48000;
-       channels->min = channels->max = 2;
-
-       /* set SSP0 to 16 bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S16_LE);
-       return 0;
-}
-
-static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
-               SND_SOC_CLOCK_IN);
-
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec sysclk configuration\n");
-               return ret;
-       }
-
-       /* set correct codec filter for DAI format and clock config */
-       snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
-
-       return ret;
-}
-
-static struct snd_soc_ops haswell_rt5640_ops = {
-       .hw_params = haswell_rt5640_hw_params,
-};
-
-static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
-       struct sst_hsw *haswell = pdata->dsp;
-       int ret;
-
-       /* Set ADSP SSP port settings */
-       ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
-               SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
-               SST_HSW_DEVICE_CLOCK_MASTER, 9);
-       if (ret < 0) {
-               dev_err(rtd->dev, "failed to set device config\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_dai_link haswell_rt5640_dais[] = {
-       /* Front End DAI links */
-       {
-               .name = "System",
-               .stream_name = "System Playback/Capture",
-               .cpu_dai_name = "System Pin",
-               .platform_name = "haswell-pcm-audio",
-               .dynamic = 1,
-               .codec_name = "snd-soc-dummy",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .init = haswell_rtd_init,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-       },
-       {
-               .name = "Offload0",
-               .stream_name = "Offload0 Playback",
-               .cpu_dai_name = "Offload0 Pin",
-               .platform_name = "haswell-pcm-audio",
-               .dynamic = 1,
-               .codec_name = "snd-soc-dummy",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-       },
-       {
-               .name = "Offload1",
-               .stream_name = "Offload1 Playback",
-               .cpu_dai_name = "Offload1 Pin",
-               .platform_name = "haswell-pcm-audio",
-               .dynamic = 1,
-               .codec_name = "snd-soc-dummy",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-       },
-       {
-               .name = "Loopback",
-               .stream_name = "Loopback",
-               .cpu_dai_name = "Loopback Pin",
-               .platform_name = "haswell-pcm-audio",
-               .dynamic = 0,
-               .codec_name = "snd-soc-dummy",
-               .codec_dai_name = "snd-soc-dummy-dai",
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_capture = 1,
-       },
-
-       /* Back End DAI links */
-       {
-               /* SSP0 - Codec */
-               .name = "Codec",
-               .be_id = 0,
-               .cpu_dai_name = "snd-soc-dummy-dai",
-               .platform_name = "snd-soc-dummy",
-               .no_pcm = 1,
-               .codec_name = "i2c-INT33CA:00",
-               .codec_dai_name = "rt5640-aif1",
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
-               .ignore_pmdown_time = 1,
-               .be_hw_params_fixup = haswell_ssp0_fixup,
-               .ops = &haswell_rt5640_ops,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-       },
-};
-
-/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
-static struct snd_soc_card haswell_rt5640 = {
-       .name = "haswell-rt5640",
-       .owner = THIS_MODULE,
-       .dai_link = haswell_rt5640_dais,
-       .num_links = ARRAY_SIZE(haswell_rt5640_dais),
-       .dapm_widgets = haswell_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
-       .dapm_routes = haswell_rt5640_map,
-       .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
-       .fully_routed = true,
-};
-
-static int haswell_audio_probe(struct platform_device *pdev)
-{
-       haswell_rt5640.dev = &pdev->dev;
-
-       return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640);
-}
-
-static struct platform_driver haswell_audio = {
-       .probe = haswell_audio_probe,
-       .driver = {
-               .name = "haswell-audio",
-       },
-};
-
-module_platform_driver(haswell_audio)
-
-/* Module information */
-MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
-MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:haswell-audio");
diff --git a/sound/soc/intel/haswell/Makefile b/sound/soc/intel/haswell/Makefile
new file mode 100644 (file)
index 0000000..9c17231
--- /dev/null
@@ -0,0 +1,4 @@
+snd-soc-sst-haswell-pcm-objs := \
+               sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o
+
+obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o
diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c
new file mode 100644 (file)
index 0000000..7f94920
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * Intel Haswell SST DSP driver
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "../haswell/sst-haswell-ipc.h"
+
+#include <trace/events/hswadsp.h>
+
+#define SST_HSW_FW_SIGNATURE_SIZE      4
+#define SST_HSW_FW_SIGN                        "$SST"
+#define SST_HSW_FW_LIB_SIGN            "$LIB"
+
+#define SST_WPT_SHIM_OFFSET    0xFB000
+#define SST_LP_SHIM_OFFSET     0xE7000
+#define SST_WPT_IRAM_OFFSET    0xA0000
+#define SST_LP_IRAM_OFFSET     0x80000
+#define SST_WPT_DSP_DRAM_OFFSET        0x400000
+#define SST_WPT_DSP_IRAM_OFFSET        0x00000
+#define SST_LPT_DSP_DRAM_OFFSET        0x400000
+#define SST_LPT_DSP_IRAM_OFFSET        0x00000
+
+#define SST_SHIM_PM_REG                0x84
+
+#define SST_HSW_IRAM   1
+#define SST_HSW_DRAM   2
+#define SST_HSW_REGS   3
+
+struct dma_block_info {
+       __le32 type;            /* IRAM/DRAM */
+       __le32 size;            /* Bytes */
+       __le32 ram_offset;      /* Offset in I/DRAM */
+       __le32 rsvd;            /* Reserved field */
+} __attribute__((packed));
+
+struct fw_module_info {
+       __le32 persistent_size;
+       __le32 scratch_size;
+} __attribute__((packed));
+
+struct fw_header {
+       unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* FW signature */
+       __le32 file_size;               /* size of fw minus this header */
+       __le32 modules;         /*  # of modules */
+       __le32 file_format;     /* version of header format */
+       __le32 reserved[4];
+} __attribute__((packed));
+
+struct fw_module_header {
+       unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* module signature */
+       __le32 mod_size;        /* size of module */
+       __le32 blocks;  /* # of blocks */
+       __le16 padding;
+       __le16 type;    /* codec type, pp lib */
+       __le32 entry_point;
+       struct fw_module_info info;
+} __attribute__((packed));
+
+static void hsw_free(struct sst_dsp *sst);
+
+static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
+       struct fw_module_header *module)
+{
+       struct dma_block_info *block;
+       struct sst_module *mod;
+       struct sst_module_template template;
+       int count, ret;
+       void __iomem *ram;
+
+       /* TODO: allowed module types need to be configurable */
+       if (module->type != SST_HSW_MODULE_BASE_FW
+               && module->type != SST_HSW_MODULE_PCM_SYSTEM
+               && module->type != SST_HSW_MODULE_PCM
+               && module->type != SST_HSW_MODULE_PCM_REFERENCE
+               && module->type != SST_HSW_MODULE_PCM_CAPTURE
+               && module->type != SST_HSW_MODULE_WAVES
+               && module->type != SST_HSW_MODULE_LPAL)
+               return 0;
+
+       dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n",
+               module->signature, module->mod_size,
+               module->blocks, module->type);
+       dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point);
+       dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n",
+               module->info.persistent_size, module->info.scratch_size);
+
+       memset(&template, 0, sizeof(template));
+       template.id = module->type;
+       template.entry = module->entry_point - 4;
+       template.persistent_size = module->info.persistent_size;
+       template.scratch_size = module->info.scratch_size;
+
+       mod = sst_module_new(fw, &template, NULL);
+       if (mod == NULL)
+               return -ENOMEM;
+
+       block = (void *)module + sizeof(*module);
+
+       for (count = 0; count < module->blocks; count++) {
+
+               if (block->size <= 0) {
+                       dev_err(dsp->dev,
+                               "error: block %d size invalid\n", count);
+                       sst_module_free(mod);
+                       return -EINVAL;
+               }
+
+               switch (block->type) {
+               case SST_HSW_IRAM:
+                       ram = dsp->addr.lpe;
+                       mod->offset =
+                               block->ram_offset + dsp->addr.iram_offset;
+                       mod->type = SST_MEM_IRAM;
+                       break;
+               case SST_HSW_DRAM:
+               case SST_HSW_REGS:
+                       ram = dsp->addr.lpe;
+                       mod->offset = block->ram_offset;
+                       mod->type = SST_MEM_DRAM;
+                       break;
+               default:
+                       dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n",
+                               block->type, count);
+                       sst_module_free(mod);
+                       return -EINVAL;
+               }
+
+               mod->size = block->size;
+               mod->data = (void *)block + sizeof(*block);
+               mod->data_offset = mod->data - fw->dma_buf;
+
+               dev_dbg(dsp->dev, "module block %d type 0x%x "
+                       "size 0x%x ==> ram %p offset 0x%x\n",
+                       count, mod->type, block->size, ram,
+                       block->ram_offset);
+
+               ret = sst_module_alloc_blocks(mod);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "error: could not allocate blocks for module %d\n",
+                               count);
+                       sst_module_free(mod);
+                       return ret;
+               }
+
+               block = (void *)block + sizeof(*block) + block->size;
+       }
+       mod->state = SST_MODULE_STATE_LOADED;
+
+       return 0;
+}
+
+static int hsw_parse_fw_image(struct sst_fw *sst_fw)
+{
+       struct fw_header *header;
+       struct fw_module_header *module;
+       struct sst_dsp *dsp = sst_fw->dsp;
+       int ret, count;
+
+       /* Read the header information from the data pointer */
+       header = (struct fw_header *)sst_fw->dma_buf;
+
+       /* verify FW */
+       if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) ||
+               (sst_fw->size != header->file_size + sizeof(*header))) {
+               dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dsp->dev, "header size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
+               header->file_size, header->modules,
+               header->file_format, sizeof(*header));
+
+       /* parse each module */
+       module = (void *)sst_fw->dma_buf + sizeof(*header);
+       for (count = 0; count < header->modules; count++) {
+
+               /* module */
+               ret = hsw_parse_module(dsp, sst_fw, module);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "error: invalid module %d\n", count);
+                       return ret;
+               }
+               module = (void *)module + sizeof(*module) + module->mod_size;
+       }
+
+       return 0;
+}
+
+static irqreturn_t hsw_irq(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       u32 isr;
+       int ret = IRQ_NONE;
+
+       spin_lock(&sst->spinlock);
+
+       /* Interrupt arrived, check src */
+       isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
+       if (isr & SST_ISRX_DONE) {
+               trace_sst_irq_done(isr,
+                       sst_dsp_shim_read_unlocked(sst, SST_IMRX));
+
+               /* Mask Done interrupt before return */
+               sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                       SST_IMRX_DONE, SST_IMRX_DONE);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       if (isr & SST_ISRX_BUSY) {
+               trace_sst_irq_busy(isr,
+                       sst_dsp_shim_read_unlocked(sst, SST_IMRX));
+
+               /* Mask Busy interrupt before return */
+               sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                       SST_IMRX_BUSY, SST_IMRX_BUSY);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       spin_unlock(&sst->spinlock);
+       return ret;
+}
+
+static void hsw_set_dsp_D3(struct sst_dsp *sst)
+{
+       u32 val;
+       u32 reg;
+
+       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
+       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       /* enable power gating and switch off DRAM & IRAM blocks */
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       val |= SST_VDRTCL0_DSRAMPGE_MASK |
+               SST_VDRTCL0_ISRAMPGE_MASK;
+       val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD);
+       writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+       /* switch off audio PLL */
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       val |= SST_VDRTCL2_APLLSE_MASK;
+       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       /* disable MCLK(clkctl.smos = 0) */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
+               SST_CLKCTL_MASK, 0);
+
+       /* Set D3 state, delay 50 us */
+       val = readl(sst->addr.pci_cfg + SST_PMCS);
+       val |= SST_PMCS_PS_MASK;
+       writel(val, sst->addr.pci_cfg + SST_PMCS);
+       udelay(50);
+
+       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
+       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       udelay(50);
+
+}
+
+static void hsw_reset(struct sst_dsp *sst)
+{
+       /* put DSP into reset and stall */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+               SST_CSR_RST | SST_CSR_STALL,
+               SST_CSR_RST | SST_CSR_STALL);
+
+       /* keep in reset for 10ms */
+       mdelay(10);
+
+       /* take DSP out of reset and keep stalled for FW loading */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+               SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
+}
+
+static int hsw_set_dsp_D0(struct sst_dsp *sst)
+{
+       int tries = 10;
+       u32 reg, fw_dump_bit;
+
+       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
+       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       reg |= SST_VDRTCL0_D3PGD;
+       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+       /* Set D0 state */
+       reg = readl(sst->addr.pci_cfg + SST_PMCS);
+       reg &= ~SST_PMCS_PS_MASK;
+       writel(reg, sst->addr.pci_cfg + SST_PMCS);
+
+       /* check that ADSP shim is enabled */
+       while (tries--) {
+               reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK;
+               if (reg == 0)
+                       goto finish;
+
+               msleep(1);
+       }
+
+       return -ENODEV;
+
+finish:
+       /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+               SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
+
+       /* stall DSP core, set clk to 192/96Mhz */
+       sst_dsp_shim_update_bits_unlocked(sst,
+               SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK,
+               SST_CSR_STALL | SST_CSR_DCS(4));
+
+       /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
+               SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
+               SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
+
+       /* Stall and reset core, set CSR */
+       hsw_reset(sst);
+
+       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
+       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       udelay(50);
+
+       /* switch on audio PLL */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       reg &= ~SST_VDRTCL2_APLLSE_MASK;
+       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       /* set default power gating control, enable power gating control for all blocks. that is,
+       can't be accessed, please enable each block before accessing. */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
+       /* for D0, always enable the block(DSRAM[0]) used for FW dump */
+       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
+       writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+
+       /* disable DMA finish function for SSP0 & SSP1 */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
+               SST_CSR2_SDFD_SSP1);
+
+       /* set on-demond mode on engine 0,1 for all channels */
+       sst_dsp_shim_update_bits(sst, SST_HMDC,
+                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
+                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH);
+
+       /* Enable Interrupt from both sides */
+       sst_dsp_shim_update_bits(sst, SST_IMRX, (SST_IMRX_BUSY | SST_IMRX_DONE),
+                                0x0);
+       sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY |
+                               SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0);
+
+       /* clear IPC registers */
+       sst_dsp_shim_write(sst, SST_IPCX, 0x0);
+       sst_dsp_shim_write(sst, SST_IPCD, 0x0);
+       sst_dsp_shim_write(sst, 0x80, 0x6);
+       sst_dsp_shim_write(sst, 0xe0, 0x300a);
+
+       return 0;
+}
+
+static void hsw_boot(struct sst_dsp *sst)
+{
+       /* set oportunistic mode on engine 0,1 for all channels */
+       sst_dsp_shim_update_bits(sst, SST_HMDC,
+                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, 0);
+
+       /* set DSP to RUN */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
+}
+
+static void hsw_stall(struct sst_dsp *sst)
+{
+       /* stall DSP */
+       sst_dsp_shim_update_bits(sst, SST_CSR,
+               SST_CSR_24MHZ_LPCS | SST_CSR_STALL,
+               SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
+}
+
+static void hsw_sleep(struct sst_dsp *sst)
+{
+       dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n");
+
+       /* put DSP into reset and stall */
+       sst_dsp_shim_update_bits(sst, SST_CSR,
+               SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL,
+               SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
+
+       hsw_set_dsp_D3(sst);
+       dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
+}
+
+static int hsw_wake(struct sst_dsp *sst)
+{
+       int ret;
+
+       dev_dbg(sst->dev, "HSW_PM dsp runtime resume\n");
+
+       ret = hsw_set_dsp_D0(sst);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(sst->dev, "HSW_PM dsp runtime resume exit\n");
+
+       return 0;
+}
+
+struct sst_adsp_memregion {
+       u32 start;
+       u32 end;
+       int blocks;
+       enum sst_mem_type type;
+};
+
+/* lynx point ADSP mem regions */
+static const struct sst_adsp_memregion lp_region[] = {
+       {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+       {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */
+       {0x80000, 0xE0000, 12, SST_MEM_IRAM}, /* I-SRAM - 12 * 32kB */
+};
+
+/* wild cat point ADSP mem regions */
+static const struct sst_adsp_memregion wpt_region[] = {
+       {0x00000, 0xA0000, 20, SST_MEM_DRAM}, /* D-SRAM0,D-SRAM1,D-SRAM2 - 20 * 32kB */
+       {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */
+};
+
+static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       /* ADSP DRAM & IRAM */
+       sst->addr.lpe_base = pdata->lpe_base;
+       sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
+       if (!sst->addr.lpe)
+               return -ENODEV;
+
+       /* ADSP PCI MMIO config space */
+       sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
+       if (!sst->addr.pci_cfg) {
+               iounmap(sst->addr.lpe);
+               return -ENODEV;
+       }
+
+       /* SST Shim */
+       sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
+       return 0;
+}
+
+struct sst_sram_shift {
+       u32 dev_id;     /* SST Device IDs  */
+       u32 iram_shift;
+       u32 dram_shift;
+};
+
+static const struct sst_sram_shift sram_shift[] = {
+       {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */
+       {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */
+};
+
+static u32 hsw_block_get_bit(struct sst_mem_block *block)
+{
+       u32 bit = 0, shift = 0, index;
+       struct sst_dsp *sst = block->dsp;
+
+       for (index = 0; index < ARRAY_SIZE(sram_shift); index++) {
+               if (sram_shift[index].dev_id == sst->id)
+                       break;
+       }
+
+       if (index < ARRAY_SIZE(sram_shift)) {
+               switch (block->type) {
+               case SST_MEM_DRAM:
+                       shift = sram_shift[index].dram_shift;
+                       break;
+               case SST_MEM_IRAM:
+                       shift = sram_shift[index].iram_shift;
+                       break;
+               default:
+                       shift = 0;
+               }
+       } else
+               shift = 0;
+
+       bit = 1 << (block->index + shift);
+
+       return bit;
+}
+
+/*dummy read a SRAM block.*/
+static void sst_mem_block_dummy_read(struct sst_mem_block *block)
+{
+       u32 size;
+       u8 tmp_buf[4];
+       struct sst_dsp *sst = block->dsp;
+
+       size = block->size > 4 ? 4 : block->size;
+       memcpy_fromio(tmp_buf, sst->addr.lpe + block->offset, size);
+}
+
+/* enable 32kB memory block - locks held by caller */
+static int hsw_block_enable(struct sst_mem_block *block)
+{
+       struct sst_dsp *sst = block->dsp;
+       u32 bit, val;
+
+       if (block->users++ > 0)
+               return 0;
+
+       dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n",
+               block->type, block->index, block->offset);
+
+       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       val &= ~SST_VDRTCL2_DCLCGE;
+       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       bit = hsw_block_get_bit(block);
+       writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+       /* wait 18 DSP clock ticks */
+       udelay(10);
+
+       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       val |= SST_VDRTCL2_DCLCGE;
+       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       udelay(50);
+
+       /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/
+       sst_mem_block_dummy_read(block);
+       return 0;
+}
+
+/* disable 32kB memory block - locks held by caller */
+static int hsw_block_disable(struct sst_mem_block *block)
+{
+       struct sst_dsp *sst = block->dsp;
+       u32 bit, val;
+
+       if (--block->users > 0)
+               return 0;
+
+       dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n",
+               block->type, block->index, block->offset);
+
+       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       val &= ~SST_VDRTCL2_DCLCGE;
+       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       bit = hsw_block_get_bit(block);
+       /* don't disable DSRAM[0], keep it always enable for FW dump*/
+       if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT))
+               writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+       /* wait 18 DSP clock ticks */
+       udelay(10);
+
+       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       val |= SST_VDRTCL2_DCLCGE;
+       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       udelay(50);
+
+       return 0;
+}
+
+static struct sst_block_ops sst_hsw_ops = {
+       .enable = hsw_block_enable,
+       .disable = hsw_block_disable,
+};
+
+static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       const struct sst_adsp_memregion *region;
+       struct device *dev;
+       int ret = -ENODEV, i, j, region_count;
+       u32 offset, size, fw_dump_bit;
+
+       dev = sst->dma_dev;
+
+       switch (sst->id) {
+       case SST_DEV_ID_LYNX_POINT:
+               region = lp_region;
+               region_count = ARRAY_SIZE(lp_region);
+               sst->addr.iram_offset = SST_LP_IRAM_OFFSET;
+               sst->addr.dsp_iram_offset = SST_LPT_DSP_IRAM_OFFSET;
+               sst->addr.dsp_dram_offset = SST_LPT_DSP_DRAM_OFFSET;
+               sst->addr.shim_offset = SST_LP_SHIM_OFFSET;
+               break;
+       case SST_DEV_ID_WILDCAT_POINT:
+               region = wpt_region;
+               region_count = ARRAY_SIZE(wpt_region);
+               sst->addr.iram_offset = SST_WPT_IRAM_OFFSET;
+               sst->addr.dsp_iram_offset = SST_WPT_DSP_IRAM_OFFSET;
+               sst->addr.dsp_dram_offset = SST_WPT_DSP_DRAM_OFFSET;
+               sst->addr.shim_offset = SST_WPT_SHIM_OFFSET;
+               break;
+       default:
+               dev_err(dev, "error: failed to get mem resources\n");
+               return ret;
+       }
+
+       ret = hsw_acpi_resource_map(sst, pdata);
+       if (ret < 0) {
+               dev_err(dev, "error: failed to map resources\n");
+               return ret;
+       }
+
+       /* enable the DSP SHIM */
+       ret = hsw_set_dsp_D0(sst);
+       if (ret < 0) {
+               dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
+               return ret;
+       }
+
+       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
+       if (ret)
+               return ret;
+
+
+       /* register DSP memory blocks - ideally we should get this from ACPI */
+       for (i = 0; i < region_count; i++) {
+               offset = region[i].start;
+               size = (region[i].end - region[i].start) / region[i].blocks;
+
+               /* register individual memory blocks */
+               for (j = 0; j < region[i].blocks; j++) {
+                       sst_mem_block_register(sst, offset, size,
+                               region[i].type, &sst_hsw_ops, j, sst);
+                       offset += size;
+               }
+       }
+
+       /* always enable the block(DSRAM[0]) used for FW dump */
+       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
+       /* set default power gating control, enable power gating control for all blocks. that is,
+       can't be accessed, please enable each block before accessing. */
+       writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+       return 0;
+}
+
+static void hsw_free(struct sst_dsp *sst)
+{
+       sst_mem_block_unregister_all(sst);
+       iounmap(sst->addr.lpe);
+       iounmap(sst->addr.pci_cfg);
+}
+
+struct sst_ops haswell_ops = {
+       .reset = hsw_reset,
+       .boot = hsw_boot,
+       .stall = hsw_stall,
+       .wake = hsw_wake,
+       .sleep = hsw_sleep,
+       .write = sst_shim32_write,
+       .read = sst_shim32_read,
+       .write64 = sst_shim32_write64,
+       .read64 = sst_shim32_read64,
+       .ram_read = sst_memcpy_fromio_32,
+       .ram_write = sst_memcpy_toio_32,
+       .irq_handler = hsw_irq,
+       .init = hsw_init,
+       .free = hsw_free,
+       .parse_fw = hsw_parse_fw_image,
+};
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c
new file mode 100644 (file)
index 0000000..344a1e9
--- /dev/null
@@ -0,0 +1,2220 @@
+/*
+ *  Intel SST Haswell/Broadwell IPC Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
+#include <sound/asound.h>
+
+#include "sst-haswell-ipc.h"
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "../common/sst-ipc.h"
+
+/* Global Message - Generic */
+#define IPC_GLB_TYPE_SHIFT     24
+#define IPC_GLB_TYPE_MASK      (0x1f << IPC_GLB_TYPE_SHIFT)
+#define IPC_GLB_TYPE(x)                (x << IPC_GLB_TYPE_SHIFT)
+
+/* Global Message - Reply */
+#define IPC_GLB_REPLY_SHIFT    0
+#define IPC_GLB_REPLY_MASK     (0x1f << IPC_GLB_REPLY_SHIFT)
+#define IPC_GLB_REPLY_TYPE(x)  (x << IPC_GLB_REPLY_TYPE_SHIFT)
+
+/* Stream Message - Generic */
+#define IPC_STR_TYPE_SHIFT     20
+#define IPC_STR_TYPE_MASK      (0xf << IPC_STR_TYPE_SHIFT)
+#define IPC_STR_TYPE(x)                (x << IPC_STR_TYPE_SHIFT)
+#define IPC_STR_ID_SHIFT       16
+#define IPC_STR_ID_MASK                (0xf << IPC_STR_ID_SHIFT)
+#define IPC_STR_ID(x)          (x << IPC_STR_ID_SHIFT)
+
+/* Stream Message - Reply */
+#define IPC_STR_REPLY_SHIFT    0
+#define IPC_STR_REPLY_MASK     (0x1f << IPC_STR_REPLY_SHIFT)
+
+/* Stream Stage Message - Generic */
+#define IPC_STG_TYPE_SHIFT     12
+#define IPC_STG_TYPE_MASK      (0xf << IPC_STG_TYPE_SHIFT)
+#define IPC_STG_TYPE(x)                (x << IPC_STG_TYPE_SHIFT)
+#define IPC_STG_ID_SHIFT       10
+#define IPC_STG_ID_MASK                (0x3 << IPC_STG_ID_SHIFT)
+#define IPC_STG_ID(x)          (x << IPC_STG_ID_SHIFT)
+
+/* Stream Stage Message - Reply */
+#define IPC_STG_REPLY_SHIFT    0
+#define IPC_STG_REPLY_MASK     (0x1f << IPC_STG_REPLY_SHIFT)
+
+/* Debug Log Message - Generic */
+#define IPC_LOG_OP_SHIFT       20
+#define IPC_LOG_OP_MASK                (0xf << IPC_LOG_OP_SHIFT)
+#define IPC_LOG_OP_TYPE(x)     (x << IPC_LOG_OP_SHIFT)
+#define IPC_LOG_ID_SHIFT       16
+#define IPC_LOG_ID_MASK                (0xf << IPC_LOG_ID_SHIFT)
+#define IPC_LOG_ID(x)          (x << IPC_LOG_ID_SHIFT)
+
+/* Module Message */
+#define IPC_MODULE_OPERATION_SHIFT     20
+#define IPC_MODULE_OPERATION_MASK      (0xf << IPC_MODULE_OPERATION_SHIFT)
+#define IPC_MODULE_OPERATION(x)        (x << IPC_MODULE_OPERATION_SHIFT)
+
+#define IPC_MODULE_ID_SHIFT    16
+#define IPC_MODULE_ID_MASK     (0xf << IPC_MODULE_ID_SHIFT)
+#define IPC_MODULE_ID(x)       (x << IPC_MODULE_ID_SHIFT)
+
+/* IPC message timeout (msecs) */
+#define IPC_TIMEOUT_MSECS      300
+#define IPC_BOOT_MSECS         200
+#define IPC_MSG_WAIT           0
+#define IPC_MSG_NOWAIT         1
+
+/* Firmware Ready Message */
+#define IPC_FW_READY           (0x1 << 29)
+#define IPC_STATUS_MASK                (0x3 << 30)
+
+#define IPC_EMPTY_LIST_SIZE    8
+#define IPC_MAX_STREAMS                4
+
+/* Mailbox */
+#define IPC_MAX_MAILBOX_BYTES  256
+
+#define INVALID_STREAM_HW_ID   0xffffffff
+
+/* Global Message - Types and Replies */
+enum ipc_glb_type {
+       IPC_GLB_GET_FW_VERSION = 0,             /* Retrieves firmware version */
+       IPC_GLB_PERFORMANCE_MONITOR = 1,        /* Performance monitoring actions */
+       IPC_GLB_ALLOCATE_STREAM = 3,            /* Request to allocate new stream */
+       IPC_GLB_FREE_STREAM = 4,                /* Request to free stream */
+       IPC_GLB_GET_FW_CAPABILITIES = 5,        /* Retrieves firmware capabilities */
+       IPC_GLB_STREAM_MESSAGE = 6,             /* Message directed to stream or its stages */
+       /* Request to store firmware context during D0->D3 transition */
+       IPC_GLB_REQUEST_DUMP = 7,
+       /* Request to restore firmware context during D3->D0 transition */
+       IPC_GLB_RESTORE_CONTEXT = 8,
+       IPC_GLB_GET_DEVICE_FORMATS = 9,         /* Set device format */
+       IPC_GLB_SET_DEVICE_FORMATS = 10,        /* Get device format */
+       IPC_GLB_SHORT_REPLY = 11,
+       IPC_GLB_ENTER_DX_STATE = 12,
+       IPC_GLB_GET_MIXER_STREAM_INFO = 13,     /* Request mixer stream params */
+       IPC_GLB_DEBUG_LOG_MESSAGE = 14,         /* Message to or from the debug logger. */
+       IPC_GLB_MODULE_OPERATION = 15,          /* Message to loadable fw module */
+       IPC_GLB_REQUEST_TRANSFER = 16,          /* < Request Transfer for host */
+       IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17,      /* Maximum message number */
+};
+
+enum ipc_glb_reply {
+       IPC_GLB_REPLY_SUCCESS = 0,              /* The operation was successful. */
+       IPC_GLB_REPLY_ERROR_INVALID_PARAM = 1,  /* Invalid parameter was passed. */
+       IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE = 2, /* Uknown message type was resceived. */
+       IPC_GLB_REPLY_OUT_OF_RESOURCES = 3,     /* No resources to satisfy the request. */
+       IPC_GLB_REPLY_BUSY = 4,                 /* The system or resource is busy. */
+       IPC_GLB_REPLY_PENDING = 5,              /* The action was scheduled for processing.  */
+       IPC_GLB_REPLY_FAILURE = 6,              /* Critical error happened. */
+       IPC_GLB_REPLY_INVALID_REQUEST = 7,      /* Request can not be completed. */
+       IPC_GLB_REPLY_STAGE_UNINITIALIZED = 8,  /* Processing stage was uninitialized. */
+       IPC_GLB_REPLY_NOT_FOUND = 9,            /* Required resource can not be found. */
+       IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10,  /* Source was not started. */
+};
+
+enum ipc_module_operation {
+       IPC_MODULE_NOTIFICATION = 0,
+       IPC_MODULE_ENABLE = 1,
+       IPC_MODULE_DISABLE = 2,
+       IPC_MODULE_GET_PARAMETER = 3,
+       IPC_MODULE_SET_PARAMETER = 4,
+       IPC_MODULE_GET_INFO = 5,
+       IPC_MODULE_MAX_MESSAGE
+};
+
+/* Stream Message - Types */
+enum ipc_str_operation {
+       IPC_STR_RESET = 0,
+       IPC_STR_PAUSE = 1,
+       IPC_STR_RESUME = 2,
+       IPC_STR_STAGE_MESSAGE = 3,
+       IPC_STR_NOTIFICATION = 4,
+       IPC_STR_MAX_MESSAGE
+};
+
+/* Stream Stage Message Types */
+enum ipc_stg_operation {
+       IPC_STG_GET_VOLUME = 0,
+       IPC_STG_SET_VOLUME,
+       IPC_STG_SET_WRITE_POSITION,
+       IPC_STG_SET_FX_ENABLE,
+       IPC_STG_SET_FX_DISABLE,
+       IPC_STG_SET_FX_GET_PARAM,
+       IPC_STG_SET_FX_SET_PARAM,
+       IPC_STG_SET_FX_GET_INFO,
+       IPC_STG_MUTE_LOOPBACK,
+       IPC_STG_MAX_MESSAGE
+};
+
+/* Stream Stage Message Types For Notification*/
+enum ipc_stg_operation_notify {
+       IPC_POSITION_CHANGED = 0,
+       IPC_STG_GLITCH,
+       IPC_STG_MAX_NOTIFY
+};
+
+enum ipc_glitch_type {
+       IPC_GLITCH_UNDERRUN = 1,
+       IPC_GLITCH_DECODER_ERROR,
+       IPC_GLITCH_DOUBLED_WRITE_POS,
+       IPC_GLITCH_MAX
+};
+
+/* Debug Control */
+enum ipc_debug_operation {
+       IPC_DEBUG_ENABLE_LOG = 0,
+       IPC_DEBUG_DISABLE_LOG = 1,
+       IPC_DEBUG_REQUEST_LOG_DUMP = 2,
+       IPC_DEBUG_NOTIFY_LOG_DUMP = 3,
+       IPC_DEBUG_MAX_DEBUG_LOG
+};
+
+/* Firmware Ready */
+struct sst_hsw_ipc_fw_ready {
+       u32 inbox_offset;
+       u32 outbox_offset;
+       u32 inbox_size;
+       u32 outbox_size;
+       u32 fw_info_size;
+       u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)];
+} __attribute__((packed));
+
+struct sst_hsw_stream;
+struct sst_hsw;
+
+/* Stream infomation */
+struct sst_hsw_stream {
+       /* configuration */
+       struct sst_hsw_ipc_stream_alloc_req request;
+       struct sst_hsw_ipc_stream_alloc_reply reply;
+       struct sst_hsw_ipc_stream_free_req free_req;
+
+       /* Mixer info */
+       u32 mute_volume[SST_HSW_NO_CHANNELS];
+       u32 mute[SST_HSW_NO_CHANNELS];
+
+       /* runtime info */
+       struct sst_hsw *hsw;
+       int host_id;
+       bool commited;
+       bool running;
+
+       /* Notification work */
+       struct work_struct notify_work;
+       u32 header;
+
+       /* Position info from DSP */
+       struct sst_hsw_ipc_stream_set_position wpos;
+       struct sst_hsw_ipc_stream_get_position rpos;
+       struct sst_hsw_ipc_stream_glitch_position glitch;
+
+       /* Volume info */
+       struct sst_hsw_ipc_volume_req vol_req;
+
+       /* driver callback */
+       u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
+       void *pdata;
+
+       /* record the fw read position when playback */
+       snd_pcm_uframes_t old_position;
+       bool play_silence;
+       struct list_head node;
+};
+
+/* FW log ring information */
+struct sst_hsw_log_stream {
+       dma_addr_t dma_addr;
+       unsigned char *dma_area;
+       unsigned char *ring_descr;
+       int pages;
+       int size;
+
+       /* Notification work */
+       struct work_struct notify_work;
+       wait_queue_head_t readers_wait_q;
+       struct mutex rw_mutex;
+
+       u32 last_pos;
+       u32 curr_pos;
+       u32 reader_pos;
+
+       /* fw log config */
+       u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
+
+       struct sst_hsw *hsw;
+};
+
+/* SST Haswell IPC data */
+struct sst_hsw {
+       struct device *dev;
+       struct sst_dsp *dsp;
+       struct platform_device *pdev_pcm;
+
+       /* FW config */
+       struct sst_hsw_ipc_fw_ready fw_ready;
+       struct sst_hsw_ipc_fw_version version;
+       bool fw_done;
+       struct sst_fw *sst_fw;
+
+       /* stream */
+       struct list_head stream_list;
+
+       /* global mixer */
+       struct sst_hsw_ipc_stream_info_reply mixer_info;
+       enum sst_hsw_volume_curve curve_type;
+       u32 curve_duration;
+       u32 mute[SST_HSW_NO_CHANNELS];
+       u32 mute_volume[SST_HSW_NO_CHANNELS];
+
+       /* DX */
+       struct sst_hsw_ipc_dx_reply dx;
+       void *dx_context;
+       dma_addr_t dx_context_paddr;
+
+       /* boot */
+       wait_queue_head_t boot_wait;
+       bool boot_complete;
+       bool shutdown;
+
+       /* IPC messaging */
+       struct sst_generic_ipc ipc;
+
+       /* FW log stream */
+       struct sst_hsw_log_stream log_stream;
+
+       /* flags bit field to track module state when resume from RTD3,
+        * each bit represent state (enabled/disabled) of single module */
+       u32 enabled_modules_rtd3;
+
+       /* buffer to store parameter lines */
+       u32 param_idx_w;        /* write index */
+       u32 param_idx_r;        /* read index */
+       u8 param_buf[WAVES_PARAM_LINES][WAVES_PARAM_COUNT];
+};
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/hswadsp.h>
+
+static inline u32 msg_get_global_type(u32 msg)
+{
+       return (msg & IPC_GLB_TYPE_MASK) >> IPC_GLB_TYPE_SHIFT;
+}
+
+static inline u32 msg_get_global_reply(u32 msg)
+{
+       return (msg & IPC_GLB_REPLY_MASK) >> IPC_GLB_REPLY_SHIFT;
+}
+
+static inline u32 msg_get_stream_type(u32 msg)
+{
+       return (msg & IPC_STR_TYPE_MASK) >>  IPC_STR_TYPE_SHIFT;
+}
+
+static inline u32 msg_get_stage_type(u32 msg)
+{
+       return (msg & IPC_STG_TYPE_MASK) >>  IPC_STG_TYPE_SHIFT;
+}
+
+static inline u32 msg_get_stream_id(u32 msg)
+{
+       return (msg & IPC_STR_ID_MASK) >>  IPC_STR_ID_SHIFT;
+}
+
+static inline u32 msg_get_notify_reason(u32 msg)
+{
+       return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
+}
+
+static inline u32 msg_get_module_operation(u32 msg)
+{
+       return (msg & IPC_MODULE_OPERATION_MASK) >> IPC_MODULE_OPERATION_SHIFT;
+}
+
+static inline u32 msg_get_module_id(u32 msg)
+{
+       return (msg & IPC_MODULE_ID_MASK) >> IPC_MODULE_ID_SHIFT;
+}
+
+u32 create_channel_map(enum sst_hsw_channel_config config)
+{
+       switch (config) {
+       case SST_HSW_CHANNEL_CONFIG_MONO:
+               return (0xFFFFFFF0 | SST_HSW_CHANNEL_CENTER);
+       case SST_HSW_CHANNEL_CONFIG_STEREO:
+               return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_RIGHT << 4));
+       case SST_HSW_CHANNEL_CONFIG_2_POINT_1:
+               return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_RIGHT << 4)
+                       | (SST_HSW_CHANNEL_LFE << 8 ));
+       case SST_HSW_CHANNEL_CONFIG_3_POINT_0:
+               return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_CENTER << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8));
+       case SST_HSW_CHANNEL_CONFIG_3_POINT_1:
+               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_CENTER << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8)
+                       | (SST_HSW_CHANNEL_LFE << 12));
+       case SST_HSW_CHANNEL_CONFIG_QUATRO:
+               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_RIGHT << 4)
+                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 8)
+                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 12));
+       case SST_HSW_CHANNEL_CONFIG_4_POINT_0:
+               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_CENTER << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8)
+                       | (SST_HSW_CHANNEL_CENTER_SURROUND << 12));
+       case SST_HSW_CHANNEL_CONFIG_5_POINT_0:
+               return (0xFFF00000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_CENTER << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8)
+                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
+                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16));
+       case SST_HSW_CHANNEL_CONFIG_5_POINT_1:
+               return (0xFF000000 | SST_HSW_CHANNEL_CENTER
+                       | (SST_HSW_CHANNEL_LEFT << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8)
+                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
+                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16)
+                       | (SST_HSW_CHANNEL_LFE << 20));
+       case SST_HSW_CHANNEL_CONFIG_DUAL_MONO:
+               return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_LEFT << 4));
+       default:
+               return 0xFFFFFFFF;
+       }
+}
+
+static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw,
+       int stream_id)
+{
+       struct sst_hsw_stream *stream;
+
+       list_for_each_entry(stream, &hsw->stream_list, node) {
+               if (stream->reply.stream_hw_id == stream_id)
+                       return stream;
+       }
+
+       return NULL;
+}
+
+static void hsw_fw_ready(struct sst_hsw *hsw, u32 header)
+{
+       struct sst_hsw_ipc_fw_ready fw_ready;
+       u32 offset;
+       u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)];
+       char *tmp[5], *pinfo;
+       int i = 0;
+
+       offset = (header & 0x1FFFFFFF) << 3;
+
+       dev_dbg(hsw->dev, "ipc: DSP is ready 0x%8.8x offset %d\n",
+               header, offset);
+
+       /* copy data from the DSP FW ready offset */
+       sst_dsp_read(hsw->dsp, &fw_ready, offset, sizeof(fw_ready));
+
+       sst_dsp_mailbox_init(hsw->dsp, fw_ready.inbox_offset,
+               fw_ready.inbox_size, fw_ready.outbox_offset,
+               fw_ready.outbox_size);
+
+       hsw->boot_complete = true;
+       wake_up(&hsw->boot_wait);
+
+       dev_dbg(hsw->dev, " mailbox upstream 0x%x - size 0x%x\n",
+               fw_ready.inbox_offset, fw_ready.inbox_size);
+       dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n",
+               fw_ready.outbox_offset, fw_ready.outbox_size);
+       if (fw_ready.fw_info_size < sizeof(fw_ready.fw_info)) {
+               fw_ready.fw_info[fw_ready.fw_info_size] = 0;
+               dev_dbg(hsw->dev, " Firmware info: %s \n", fw_ready.fw_info);
+
+               /* log the FW version info got from the mailbox here. */
+               memcpy(fw_info, fw_ready.fw_info, fw_ready.fw_info_size);
+               pinfo = &fw_info[0];
+               for (i = 0; i < ARRAY_SIZE(tmp); i++)
+                       tmp[i] = strsep(&pinfo, " ");
+               dev_info(hsw->dev, "FW loaded, mailbox readback FW info: type %s, - "
+                       "version: %s.%s, build %s, source commit id: %s\n",
+                       tmp[0], tmp[1], tmp[2], tmp[3], tmp[4]);
+       }
+}
+
+static void hsw_notification_work(struct work_struct *work)
+{
+       struct sst_hsw_stream *stream = container_of(work,
+                       struct sst_hsw_stream, notify_work);
+       struct sst_hsw_ipc_stream_glitch_position *glitch = &stream->glitch;
+       struct sst_hsw_ipc_stream_get_position *pos = &stream->rpos;
+       struct sst_hsw *hsw = stream->hsw;
+       u32 reason;
+
+       reason = msg_get_notify_reason(stream->header);
+
+       switch (reason) {
+       case IPC_STG_GLITCH:
+               trace_ipc_notification("DSP stream under/overrun",
+                       stream->reply.stream_hw_id);
+               sst_dsp_inbox_read(hsw->dsp, glitch, sizeof(*glitch));
+
+               dev_err(hsw->dev, "glitch %d pos 0x%x write pos 0x%x\n",
+                       glitch->glitch_type, glitch->present_pos,
+                       glitch->write_pos);
+               break;
+
+       case IPC_POSITION_CHANGED:
+               trace_ipc_notification("DSP stream position changed for",
+                       stream->reply.stream_hw_id);
+               sst_dsp_inbox_read(hsw->dsp, pos, sizeof(*pos));
+
+               if (stream->notify_position)
+                       stream->notify_position(stream, stream->pdata);
+
+               break;
+       default:
+               dev_err(hsw->dev, "error: unknown notification 0x%x\n",
+                       stream->header);
+               break;
+       }
+
+       /* tell DSP that notification has been handled */
+       sst_dsp_shim_update_bits(hsw->dsp, SST_IPCD,
+               SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
+
+       /* unmask busy interrupt */
+       sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
+}
+
+static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg)
+{
+       struct sst_hsw_stream *stream;
+       u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
+       u32 stream_id = msg_get_stream_id(header);
+       u32 stream_msg = msg_get_stream_type(header);
+
+       stream = get_stream_by_id(hsw, stream_id);
+       if (stream == NULL)
+               return;
+
+       switch (stream_msg) {
+       case IPC_STR_STAGE_MESSAGE:
+       case IPC_STR_NOTIFICATION:
+               break;
+       case IPC_STR_RESET:
+               trace_ipc_notification("stream reset", stream->reply.stream_hw_id);
+               break;
+       case IPC_STR_PAUSE:
+               stream->running = false;
+               trace_ipc_notification("stream paused",
+                       stream->reply.stream_hw_id);
+               break;
+       case IPC_STR_RESUME:
+               stream->running = true;
+               trace_ipc_notification("stream running",
+                       stream->reply.stream_hw_id);
+               break;
+       }
+}
+
+static int hsw_process_reply(struct sst_hsw *hsw, u32 header)
+{
+       struct ipc_message *msg;
+       u32 reply = msg_get_global_reply(header);
+
+       trace_ipc_reply("processing -->", header);
+
+       msg = sst_ipc_reply_find_msg(&hsw->ipc, header);
+       if (msg == NULL) {
+               trace_ipc_error("error: can't find message header", header);
+               return -EIO;
+       }
+
+       /* first process the header */
+       switch (reply) {
+       case IPC_GLB_REPLY_PENDING:
+               trace_ipc_pending_reply("received", header);
+               msg->pending = true;
+               hsw->ipc.pending = true;
+               return 1;
+       case IPC_GLB_REPLY_SUCCESS:
+               if (msg->pending) {
+                       trace_ipc_pending_reply("completed", header);
+                       sst_dsp_inbox_read(hsw->dsp, msg->rx_data,
+                               msg->rx_size);
+                       hsw->ipc.pending = false;
+               } else {
+                       /* copy data from the DSP */
+                       sst_dsp_outbox_read(hsw->dsp, msg->rx_data,
+                               msg->rx_size);
+               }
+               break;
+       /* these will be rare - but useful for debug */
+       case IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE:
+               trace_ipc_error("error: unknown message type", header);
+               msg->errno = -EBADMSG;
+               break;
+       case IPC_GLB_REPLY_OUT_OF_RESOURCES:
+               trace_ipc_error("error: out of resources", header);
+               msg->errno = -ENOMEM;
+               break;
+       case IPC_GLB_REPLY_BUSY:
+               trace_ipc_error("error: reply busy", header);
+               msg->errno = -EBUSY;
+               break;
+       case IPC_GLB_REPLY_FAILURE:
+               trace_ipc_error("error: reply failure", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_STAGE_UNINITIALIZED:
+               trace_ipc_error("error: stage uninitialized", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_NOT_FOUND:
+               trace_ipc_error("error: reply not found", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_SOURCE_NOT_STARTED:
+               trace_ipc_error("error: source not started", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_INVALID_REQUEST:
+               trace_ipc_error("error: invalid request", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_ERROR_INVALID_PARAM:
+               trace_ipc_error("error: invalid parameter", header);
+               msg->errno = -EINVAL;
+               break;
+       default:
+               trace_ipc_error("error: unknown reply", header);
+               msg->errno = -EINVAL;
+               break;
+       }
+
+       /* update any stream states */
+       if (msg_get_global_type(header) == IPC_GLB_STREAM_MESSAGE)
+               hsw_stream_update(hsw, msg);
+
+       /* wake up and return the error if we have waiters on this message ? */
+       list_del(&msg->list);
+       sst_ipc_tx_msg_reply_complete(&hsw->ipc, msg);
+
+       return 1;
+}
+
+static int hsw_module_message(struct sst_hsw *hsw, u32 header)
+{
+       u32 operation, module_id;
+       int handled = 0;
+
+       operation = msg_get_module_operation(header);
+       module_id = msg_get_module_id(header);
+       dev_dbg(hsw->dev, "received module message header: 0x%8.8x\n",
+                       header);
+       dev_dbg(hsw->dev, "operation: 0x%8.8x module_id: 0x%8.8x\n",
+                       operation, module_id);
+
+       switch (operation) {
+       case IPC_MODULE_NOTIFICATION:
+               dev_dbg(hsw->dev, "module notification received");
+               handled = 1;
+               break;
+       default:
+               handled = hsw_process_reply(hsw, header);
+               break;
+       }
+
+       return handled;
+}
+
+static int hsw_stream_message(struct sst_hsw *hsw, u32 header)
+{
+       u32 stream_msg, stream_id, stage_type;
+       struct sst_hsw_stream *stream;
+       int handled = 0;
+
+       stream_msg = msg_get_stream_type(header);
+       stream_id = msg_get_stream_id(header);
+       stage_type = msg_get_stage_type(header);
+
+       stream = get_stream_by_id(hsw, stream_id);
+       if (stream == NULL)
+               return handled;
+
+       stream->header = header;
+
+       switch (stream_msg) {
+       case IPC_STR_STAGE_MESSAGE:
+               dev_err(hsw->dev, "error: stage msg not implemented 0x%8.8x\n",
+                       header);
+               break;
+       case IPC_STR_NOTIFICATION:
+               schedule_work(&stream->notify_work);
+               break;
+       default:
+               /* handle pending message complete request */
+               handled = hsw_process_reply(hsw, header);
+               break;
+       }
+
+       return handled;
+}
+
+static int hsw_log_message(struct sst_hsw *hsw, u32 header)
+{
+       u32 operation = (header & IPC_LOG_OP_MASK) >>  IPC_LOG_OP_SHIFT;
+       struct sst_hsw_log_stream *stream = &hsw->log_stream;
+       int ret = 1;
+
+       if (operation != IPC_DEBUG_REQUEST_LOG_DUMP) {
+               dev_err(hsw->dev,
+                       "error: log msg not implemented 0x%8.8x\n", header);
+               return 0;
+       }
+
+       mutex_lock(&stream->rw_mutex);
+       stream->last_pos = stream->curr_pos;
+       sst_dsp_inbox_read(
+               hsw->dsp, &stream->curr_pos, sizeof(stream->curr_pos));
+       mutex_unlock(&stream->rw_mutex);
+
+       schedule_work(&stream->notify_work);
+
+       return ret;
+}
+
+static int hsw_process_notification(struct sst_hsw *hsw)
+{
+       struct sst_dsp *sst = hsw->dsp;
+       u32 type, header;
+       int handled = 1;
+
+       header = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+       type = msg_get_global_type(header);
+
+       trace_ipc_request("processing -->", header);
+
+       /* FW Ready is a special case */
+       if (!hsw->boot_complete && header & IPC_FW_READY) {
+               hsw_fw_ready(hsw, header);
+               return handled;
+       }
+
+       switch (type) {
+       case IPC_GLB_GET_FW_VERSION:
+       case IPC_GLB_ALLOCATE_STREAM:
+       case IPC_GLB_FREE_STREAM:
+       case IPC_GLB_GET_FW_CAPABILITIES:
+       case IPC_GLB_REQUEST_DUMP:
+       case IPC_GLB_GET_DEVICE_FORMATS:
+       case IPC_GLB_SET_DEVICE_FORMATS:
+       case IPC_GLB_ENTER_DX_STATE:
+       case IPC_GLB_GET_MIXER_STREAM_INFO:
+       case IPC_GLB_MAX_IPC_MESSAGE_TYPE:
+       case IPC_GLB_RESTORE_CONTEXT:
+       case IPC_GLB_SHORT_REPLY:
+               dev_err(hsw->dev, "error: message type %d header 0x%x\n",
+                       type, header);
+               break;
+       case IPC_GLB_STREAM_MESSAGE:
+               handled = hsw_stream_message(hsw, header);
+               break;
+       case IPC_GLB_DEBUG_LOG_MESSAGE:
+               handled = hsw_log_message(hsw, header);
+               break;
+       case IPC_GLB_MODULE_OPERATION:
+               handled = hsw_module_message(hsw, header);
+               break;
+       default:
+               dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n",
+                       type, header);
+               break;
+       }
+
+       return handled;
+}
+
+static irqreturn_t hsw_irq_thread(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       struct sst_hsw *hsw = sst_dsp_get_thread_context(sst);
+       struct sst_generic_ipc *ipc = &hsw->ipc;
+       u32 ipcx, ipcd;
+       int handled;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+
+       ipcx = sst_dsp_ipc_msg_rx(hsw->dsp);
+       ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+
+       /* reply message from DSP */
+       if (ipcx & SST_IPCX_DONE) {
+
+               /* Handle Immediate reply from DSP Core */
+               handled = hsw_process_reply(hsw, ipcx);
+
+               if (handled > 0) {
+                       /* clear DONE bit - tell DSP we have completed */
+                       sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
+                               SST_IPCX_DONE, 0);
+
+                       /* unmask Done interrupt */
+                       sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                               SST_IMRX_DONE, 0);
+               }
+       }
+
+       /* new message from DSP */
+       if (ipcd & SST_IPCD_BUSY) {
+
+               /* Handle Notification and Delayed reply from DSP Core */
+               handled = hsw_process_notification(hsw);
+
+               /* clear BUSY bit and set DONE bit - accept new messages */
+               if (handled > 0) {
+                       sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
+                               SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
+
+                       /* unmask busy interrupt */
+                       sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                               SST_IMRX_BUSY, 0);
+               }
+       }
+
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       /* continue to send any remaining messages... */
+       queue_kthread_work(&ipc->kworker, &ipc->kwork);
+
+       return IRQ_HANDLED;
+}
+
+int sst_hsw_fw_get_version(struct sst_hsw *hsw,
+       struct sst_hsw_ipc_fw_version *version)
+{
+       int ret;
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc,
+               IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION),
+               NULL, 0, version, sizeof(*version));
+       if (ret < 0)
+               dev_err(hsw->dev, "error: get version failed\n");
+
+       return ret;
+}
+
+/* Mixer Controls */
+int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 stage_id, u32 channel, u32 *volume)
+{
+       if (channel > 1)
+               return -EINVAL;
+
+       sst_dsp_read(hsw->dsp, volume,
+               stream->reply.volume_register_address[channel],
+               sizeof(*volume));
+
+       return 0;
+}
+
+/* stream volume */
+int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume)
+{
+       struct sst_hsw_ipc_volume_req *req;
+       u32 header;
+       int ret;
+
+       trace_ipc_request("set stream volume", stream->reply.stream_hw_id);
+
+       if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL)
+               return -EINVAL;
+
+       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
+               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
+       header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
+       header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
+       header |= (stage_id << IPC_STG_ID_SHIFT);
+
+       req = &stream->vol_req;
+       req->target_volume = volume;
+
+       /* set both at same time ? */
+       if (channel == SST_HSW_CHANNELS_ALL) {
+               if (hsw->mute[0] && hsw->mute[1]) {
+                       hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
+                       return 0;
+               } else if (hsw->mute[0])
+                       req->channel = 1;
+               else if (hsw->mute[1])
+                       req->channel = 0;
+               else
+                       req->channel = SST_HSW_CHANNELS_ALL;
+       } else {
+               /* set only 1 channel */
+               if (hsw->mute[channel]) {
+                       hsw->mute_volume[channel] = volume;
+                       return 0;
+               }
+               req->channel = channel;
+       }
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header, req,
+               sizeof(*req), NULL, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: set stream volume failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+       u32 *volume)
+{
+       if (channel > 1)
+               return -EINVAL;
+
+       sst_dsp_read(hsw->dsp, volume,
+               hsw->mixer_info.volume_register_address[channel],
+               sizeof(*volume));
+
+       return 0;
+}
+
+/* global mixer volume */
+int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+       u32 volume)
+{
+       struct sst_hsw_ipc_volume_req req;
+       u32 header;
+       int ret;
+
+       trace_ipc_request("set mixer volume", volume);
+
+       if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL)
+               return -EINVAL;
+
+       /* set both at same time ? */
+       if (channel == SST_HSW_CHANNELS_ALL) {
+               if (hsw->mute[0] && hsw->mute[1]) {
+                       hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
+                       return 0;
+               } else if (hsw->mute[0])
+                       req.channel = 1;
+               else if (hsw->mute[1])
+                       req.channel = 0;
+               else
+                       req.channel = SST_HSW_CHANNELS_ALL;
+       } else {
+               /* set only 1 channel */
+               if (hsw->mute[channel]) {
+                       hsw->mute_volume[channel] = volume;
+                       return 0;
+               }
+               req.channel = channel;
+       }
+
+       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
+               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
+       header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT);
+       header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
+       header |= (stage_id << IPC_STG_ID_SHIFT);
+
+       req.curve_duration = hsw->curve_duration;
+       req.curve_type = hsw->curve_type;
+       req.target_volume = volume;
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &req,
+               sizeof(req), NULL, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: set mixer volume failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/* Stream API */
+struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
+       u32 (*notify_position)(struct sst_hsw_stream *stream, void *data),
+       void *data)
+{
+       struct sst_hsw_stream *stream;
+       struct sst_dsp *sst = hsw->dsp;
+       unsigned long flags;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (stream == NULL)
+               return NULL;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       stream->reply.stream_hw_id = INVALID_STREAM_HW_ID;
+       list_add(&stream->node, &hsw->stream_list);
+       stream->notify_position = notify_position;
+       stream->pdata = data;
+       stream->hsw = hsw;
+       stream->host_id = id;
+
+       /* work to process notification messages */
+       INIT_WORK(&stream->notify_work, hsw_notification_work);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return stream;
+}
+
+int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+       u32 header;
+       int ret = 0;
+       struct sst_dsp *sst = hsw->dsp;
+       unsigned long flags;
+
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to free, ignore it.\n");
+               return 0;
+       }
+
+       /* dont free DSP streams that are not commited */
+       if (!stream->commited)
+               goto out;
+
+       trace_ipc_request("stream free", stream->host_id);
+
+       stream->free_req.stream_id = stream->reply.stream_hw_id;
+       header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM);
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &stream->free_req,
+               sizeof(stream->free_req), NULL, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: free stream %d failed\n",
+                       stream->free_req.stream_id);
+               return -EAGAIN;
+       }
+
+       trace_hsw_stream_free_req(stream, &stream->free_req);
+
+out:
+       cancel_work_sync(&stream->notify_work);
+       spin_lock_irqsave(&sst->spinlock, flags);
+       list_del(&stream->node);
+       kfree(stream);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return ret;
+}
+
+int sst_hsw_stream_set_bits(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, enum sst_hsw_bitdepth bits)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set bits\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.bitdepth = bits;
+       return 0;
+}
+
+int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, int channels)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set channels\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.ch_num = channels;
+       return 0;
+}
+
+int sst_hsw_stream_set_rate(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, int rate)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set rate\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.frequency = rate;
+       return 0;
+}
+
+int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 map,
+       enum sst_hsw_channel_config config)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set map\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.map = map;
+       stream->request.format.config = config;
+       return 0;
+}
+
+int sst_hsw_stream_set_style(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, enum sst_hsw_interleaving style)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set style\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.style = style;
+       return 0;
+}
+
+int sst_hsw_stream_set_valid(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 bits)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set valid bits\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.valid_bit = bits;
+       return 0;
+}
+
+/* Stream Configuration */
+int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       enum sst_hsw_stream_path_id path_id,
+       enum sst_hsw_stream_type stream_type,
+       enum sst_hsw_stream_format format_id)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set format\n");
+               return -EINVAL;
+       }
+
+       stream->request.path_id = path_id;
+       stream->request.stream_type = stream_type;
+       stream->request.format_id = format_id;
+
+       trace_hsw_stream_alloc_request(stream, &stream->request);
+
+       return 0;
+}
+
+int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 ring_pt_address, u32 num_pages,
+       u32 ring_size, u32 ring_offset, u32 ring_first_pfn)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for buffer\n");
+               return -EINVAL;
+       }
+
+       stream->request.ringinfo.ring_pt_address = ring_pt_address;
+       stream->request.ringinfo.num_pages = num_pages;
+       stream->request.ringinfo.ring_size = ring_size;
+       stream->request.ringinfo.ring_offset = ring_offset;
+       stream->request.ringinfo.ring_first_pfn = ring_first_pfn;
+
+       trace_hsw_stream_buffer(stream);
+
+       return 0;
+}
+
+int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, struct sst_module_runtime *runtime)
+{
+       struct sst_hsw_module_map *map = &stream->request.map;
+       struct sst_dsp *dsp = sst_hsw_get_dsp(hsw);
+       struct sst_module *module = runtime->module;
+
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set module\n");
+               return -EINVAL;
+       }
+
+       /* only support initial module atm */
+       map->module_entries_count = 1;
+       map->module_entries[0].module_id = module->id;
+       map->module_entries[0].entry_point = module->entry;
+
+       stream->request.persistent_mem.offset =
+               sst_dsp_get_offset(dsp, runtime->persistent_offset, SST_MEM_DRAM);
+       stream->request.persistent_mem.size = module->persistent_size;
+
+       stream->request.scratch_mem.offset =
+               sst_dsp_get_offset(dsp, dsp->scratch_offset, SST_MEM_DRAM);
+       stream->request.scratch_mem.size = dsp->scratch_size;
+
+       dev_dbg(hsw->dev, "module %d runtime %d using:\n", module->id,
+               runtime->id);
+       dev_dbg(hsw->dev, " persistent offset 0x%x bytes 0x%x\n",
+               stream->request.persistent_mem.offset,
+               stream->request.persistent_mem.size);
+       dev_dbg(hsw->dev, " scratch offset 0x%x bytes 0x%x\n",
+               stream->request.scratch_mem.offset,
+               stream->request.scratch_mem.size);
+
+       return 0;
+}
+
+int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+       struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request;
+       struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply;
+       u32 header;
+       int ret;
+
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to commit, ignore it.\n");
+               return 0;
+       }
+
+       if (stream->commited) {
+               dev_warn(hsw->dev, "warning: stream is already committed, ignore it.\n");
+               return 0;
+       }
+
+       trace_ipc_request("stream alloc", stream->host_id);
+
+       header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM);
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header, str_req,
+               sizeof(*str_req), reply, sizeof(*reply));
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: stream commit failed\n");
+               return ret;
+       }
+
+       stream->commited = 1;
+       trace_hsw_stream_alloc_reply(stream);
+
+       return 0;
+}
+
+snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       return stream->old_position;
+}
+
+void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, snd_pcm_uframes_t val)
+{
+       stream->old_position = val;
+}
+
+bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       return stream->play_silence;
+}
+
+void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, bool val)
+{
+       stream->play_silence = val;
+}
+
+/* Stream Information - these calls could be inline but we want the IPC
+ ABI to be opaque to client PCM drivers to cope with any future ABI changes */
+int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
+{
+       struct sst_hsw_ipc_stream_info_reply *reply;
+       u32 header;
+       int ret;
+
+       reply = &hsw->mixer_info;
+       header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO);
+
+       trace_ipc_request("get global mixer info", 0);
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0,
+               reply, sizeof(*reply));
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: get stream info failed\n");
+               return ret;
+       }
+
+       trace_hsw_mixer_info_reply(reply);
+
+       return 0;
+}
+
+/* Send stream command */
+static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type,
+       int stream_id, int wait)
+{
+       u32 header;
+
+       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type);
+       header |= (stream_id << IPC_STR_ID_SHIFT);
+
+       if (wait)
+               return sst_ipc_tx_message_wait(&hsw->ipc, header,
+                       NULL, 0, NULL, 0);
+       else
+               return sst_ipc_tx_message_nowait(&hsw->ipc, header, NULL, 0);
+}
+
+/* Stream ALSA trigger operations */
+int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int wait)
+{
+       int ret;
+
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to pause, ignore it.\n");
+               return 0;
+       }
+
+       trace_ipc_request("stream pause", stream->reply.stream_hw_id);
+
+       ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE,
+               stream->reply.stream_hw_id, wait);
+       if (ret < 0)
+               dev_err(hsw->dev, "error: failed to pause stream %d\n",
+                       stream->reply.stream_hw_id);
+
+       return ret;
+}
+
+int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int wait)
+{
+       int ret;
+
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to resume, ignore it.\n");
+               return 0;
+       }
+
+       trace_ipc_request("stream resume", stream->reply.stream_hw_id);
+
+       ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME,
+               stream->reply.stream_hw_id, wait);
+       if (ret < 0)
+               dev_err(hsw->dev, "error: failed to resume stream %d\n",
+                       stream->reply.stream_hw_id);
+
+       return ret;
+}
+
+int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+       int ret, tries = 10;
+
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to reset, ignore it.\n");
+               return 0;
+       }
+
+       /* dont reset streams that are not commited */
+       if (!stream->commited)
+               return 0;
+
+       /* wait for pause to complete before we reset the stream */
+       while (stream->running && tries--)
+               msleep(1);
+       if (!tries) {
+               dev_err(hsw->dev, "error: reset stream %d still running\n",
+                       stream->reply.stream_hw_id);
+               return -EINVAL;
+       }
+
+       trace_ipc_request("stream reset", stream->reply.stream_hw_id);
+
+       ret = sst_hsw_stream_operations(hsw, IPC_STR_RESET,
+               stream->reply.stream_hw_id, 1);
+       if (ret < 0)
+               dev_err(hsw->dev, "error: failed to reset stream %d\n",
+                       stream->reply.stream_hw_id);
+       return ret;
+}
+
+/* Stream pointer positions */
+u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       u32 rpos;
+
+       sst_dsp_read(hsw->dsp, &rpos,
+               stream->reply.read_position_register_address, sizeof(rpos));
+
+       return rpos;
+}
+
+/* Stream presentation (monotonic) positions */
+u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       u64 ppos;
+
+       sst_dsp_read(hsw->dsp, &ppos,
+               stream->reply.presentation_position_register_address,
+               sizeof(ppos));
+
+       return ppos;
+}
+
+/* physical BE config */
+int sst_hsw_device_set_config(struct sst_hsw *hsw,
+       enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
+       enum sst_hsw_device_mode mode, u32 clock_divider)
+{
+       struct sst_hsw_ipc_device_config_req config;
+       u32 header;
+       int ret;
+
+       trace_ipc_request("set device config", dev);
+
+       config.ssp_interface = dev;
+       config.clock_frequency = mclk;
+       config.mode = mode;
+       config.clock_divider = clock_divider;
+       if (mode == SST_HSW_DEVICE_TDM_CLOCK_MASTER)
+               config.channels = 4;
+       else
+               config.channels = 2;
+
+       trace_hsw_device_config_req(&config);
+
+       header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS);
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &config,
+               sizeof(config), NULL, 0);
+       if (ret < 0)
+               dev_err(hsw->dev, "error: set device formats failed\n");
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_hsw_device_set_config);
+
+/* DX Config */
+int sst_hsw_dx_set_state(struct sst_hsw *hsw,
+       enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx)
+{
+       u32 header, state_;
+       int ret, item;
+
+       header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE);
+       state_ = state;
+
+       trace_ipc_request("PM enter Dx state", state);
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &state_,
+               sizeof(state_), dx, sizeof(*dx));
+       if (ret < 0) {
+               dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state);
+               return ret;
+       }
+
+       for (item = 0; item < dx->entries_no; item++) {
+               dev_dbg(hsw->dev,
+                       "Item[%d] offset[%x] - size[%x] - source[%x]\n",
+                       item, dx->mem_info[item].offset,
+                       dx->mem_info[item].size,
+                       dx->mem_info[item].source);
+       }
+       dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n",
+               dx->entries_no, state);
+
+       return ret;
+}
+
+struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
+       int mod_id, int offset)
+{
+       struct sst_dsp *dsp = hsw->dsp;
+       struct sst_module *module;
+       struct sst_module_runtime *runtime;
+       int err;
+
+       module = sst_module_get_from_id(dsp, mod_id);
+       if (module == NULL) {
+               dev_err(dsp->dev, "error: failed to get module %d for pcm\n",
+                       mod_id);
+               return NULL;
+       }
+
+       runtime = sst_module_runtime_new(module, mod_id, NULL);
+       if (runtime == NULL) {
+               dev_err(dsp->dev, "error: failed to create module %d runtime\n",
+                       mod_id);
+               return NULL;
+       }
+
+       err = sst_module_runtime_alloc_blocks(runtime, offset);
+       if (err < 0) {
+               dev_err(dsp->dev, "error: failed to alloc blocks for module %d runtime\n",
+                       mod_id);
+               sst_module_runtime_free(runtime);
+               return NULL;
+       }
+
+       dev_dbg(dsp->dev, "runtime id %d created for module %d\n", runtime->id,
+               mod_id);
+       return runtime;
+}
+
+void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime)
+{
+       sst_module_runtime_free_blocks(runtime);
+       sst_module_runtime_free(runtime);
+}
+
+#ifdef CONFIG_PM
+static int sst_hsw_dx_state_dump(struct sst_hsw *hsw)
+{
+       struct sst_dsp *sst = hsw->dsp;
+       u32 item, offset, size;
+       int ret = 0;
+
+       trace_ipc_request("PM state dump. Items #", SST_HSW_MAX_DX_REGIONS);
+
+       if (hsw->dx.entries_no > SST_HSW_MAX_DX_REGIONS) {
+               dev_err(hsw->dev,
+                       "error: number of FW context regions greater than %d\n",
+                       SST_HSW_MAX_DX_REGIONS);
+               memset(&hsw->dx, 0, sizeof(hsw->dx));
+               return -EINVAL;
+       }
+
+       ret = sst_dsp_dma_get_channel(sst, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
+               return ret;
+       }
+
+       /* set on-demond mode on engine 0 channel 3 */
+       sst_dsp_shim_update_bits(sst, SST_HMDC,
+                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
+                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH);
+
+       for (item = 0; item < hsw->dx.entries_no; item++) {
+               if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP
+                       && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET
+                       && hsw->dx.mem_info[item].offset <
+                       DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) {
+
+                       offset = hsw->dx.mem_info[item].offset
+                                       - DSP_DRAM_ADDR_OFFSET;
+                       size = (hsw->dx.mem_info[item].size + 3) & (~3);
+
+                       ret = sst_dsp_dma_copyfrom(sst, hsw->dx_context_paddr + offset,
+                               sst->addr.lpe_base + offset, size);
+                       if (ret < 0) {
+                               dev_err(hsw->dev,
+                                       "error: FW context dump failed\n");
+                               memset(&hsw->dx, 0, sizeof(hsw->dx));
+                               goto out;
+                       }
+               }
+       }
+
+out:
+       sst_dsp_dma_put_channel(sst);
+       return ret;
+}
+
+static int sst_hsw_dx_state_restore(struct sst_hsw *hsw)
+{
+       struct sst_dsp *sst = hsw->dsp;
+       u32 item, offset, size;
+       int ret;
+
+       for (item = 0; item < hsw->dx.entries_no; item++) {
+               if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP
+                       && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET
+                       && hsw->dx.mem_info[item].offset <
+                       DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) {
+
+                       offset = hsw->dx.mem_info[item].offset
+                                       - DSP_DRAM_ADDR_OFFSET;
+                       size = (hsw->dx.mem_info[item].size + 3) & (~3);
+
+                       ret = sst_dsp_dma_copyto(sst, sst->addr.lpe_base + offset,
+                               hsw->dx_context_paddr + offset, size);
+                       if (ret < 0) {
+                               dev_err(hsw->dev,
+                                       "error: FW context restore failed\n");
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int sst_hsw_dsp_load(struct sst_hsw *hsw)
+{
+       struct sst_dsp *dsp = hsw->dsp;
+       struct sst_fw *sst_fw, *t;
+       int ret;
+
+       dev_dbg(hsw->dev, "loading audio DSP....");
+
+       ret = sst_dsp_wake(dsp);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: failed to wake audio DSP\n");
+               return -ENODEV;
+       }
+
+       ret = sst_dsp_dma_get_channel(dsp, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
+               return ret;
+       }
+
+       list_for_each_entry_safe_reverse(sst_fw, t, &dsp->fw_list, list) {
+               ret = sst_fw_reload(sst_fw);
+               if (ret < 0) {
+                       dev_err(hsw->dev, "error: SST FW reload failed\n");
+                       sst_dsp_dma_put_channel(dsp);
+                       return -ENOMEM;
+               }
+       }
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               return -EINVAL;
+
+       sst_dsp_dma_put_channel(dsp);
+       return 0;
+}
+
+static int sst_hsw_dsp_restore(struct sst_hsw *hsw)
+{
+       struct sst_dsp *dsp = hsw->dsp;
+       int ret;
+
+       dev_dbg(hsw->dev, "restoring audio DSP....");
+
+       ret = sst_dsp_dma_get_channel(dsp, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
+               return ret;
+       }
+
+       ret = sst_hsw_dx_state_restore(hsw);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: SST FW context restore failed\n");
+               sst_dsp_dma_put_channel(dsp);
+               return -ENOMEM;
+       }
+       sst_dsp_dma_put_channel(dsp);
+
+       /* wait for DSP boot completion */
+       sst_dsp_boot(dsp);
+
+       return ret;
+}
+
+int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw)
+{
+       int ret;
+
+       dev_dbg(hsw->dev, "audio dsp runtime suspend\n");
+
+       ret = sst_hsw_dx_set_state(hsw, SST_HSW_DX_STATE_D3, &hsw->dx);
+       if (ret < 0)
+               return ret;
+
+       sst_dsp_stall(hsw->dsp);
+
+       ret = sst_hsw_dx_state_dump(hsw);
+       if (ret < 0)
+               return ret;
+
+       sst_ipc_drop_all(&hsw->ipc);
+
+       return 0;
+}
+
+int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw)
+{
+       struct sst_fw *sst_fw, *t;
+       struct sst_dsp *dsp = hsw->dsp;
+
+       list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
+               sst_fw_unload(sst_fw);
+       }
+       sst_block_free_scratch(dsp);
+
+       hsw->boot_complete = false;
+
+       sst_dsp_sleep(dsp);
+
+       return 0;
+}
+
+int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw)
+{
+       struct device *dev = hsw->dev;
+       int ret;
+
+       dev_dbg(dev, "audio dsp runtime resume\n");
+
+       if (hsw->boot_complete)
+               return 1; /* tell caller no action is required */
+
+       ret = sst_hsw_dsp_restore(hsw);
+       if (ret < 0)
+               dev_err(dev, "error: audio DSP boot failure\n");
+
+       sst_hsw_init_module_state(hsw);
+
+       ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
+               msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (ret == 0) {
+               dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n",
+                       sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD),
+                       sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX));
+               return -EIO;
+       }
+
+       /* Set ADSP SSP port settings */
+       ret = sst_hsw_device_set_config(hsw, SST_HSW_DEVICE_SSP_0,
+                                       SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
+                                       SST_HSW_DEVICE_CLOCK_MASTER, 9);
+       if (ret < 0)
+               dev_err(dev, "error: SSP re-initialization failed\n");
+
+       return ret;
+}
+#endif
+
+struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw)
+{
+       return hsw->dsp;
+}
+
+void sst_hsw_init_module_state(struct sst_hsw *hsw)
+{
+       struct sst_module *module;
+       enum sst_hsw_module_id id;
+
+       /* the base fw contains several modules */
+       for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) {
+               module = sst_module_get_from_id(hsw->dsp, id);
+               if (module) {
+                       /* module waves is active only after being enabled */
+                       if (id == SST_HSW_MODULE_WAVES)
+                               module->state = SST_MODULE_STATE_INITIALIZED;
+                       else
+                               module->state = SST_MODULE_STATE_ACTIVE;
+               }
+       }
+}
+
+bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id)
+{
+       struct sst_module *module;
+
+       module = sst_module_get_from_id(hsw->dsp, module_id);
+       if (module == NULL || module->state == SST_MODULE_STATE_UNLOADED)
+               return false;
+       else
+               return true;
+}
+
+bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id)
+{
+       struct sst_module *module;
+
+       module = sst_module_get_from_id(hsw->dsp, module_id);
+       if (module != NULL && module->state == SST_MODULE_STATE_ACTIVE)
+               return true;
+       else
+               return false;
+}
+
+void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id)
+{
+       hsw->enabled_modules_rtd3 |= (1 << module_id);
+}
+
+void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id)
+{
+       hsw->enabled_modules_rtd3 &= ~(1 << module_id);
+}
+
+bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id)
+{
+       return hsw->enabled_modules_rtd3 & (1 << module_id);
+}
+
+void sst_hsw_reset_param_buf(struct sst_hsw *hsw)
+{
+       hsw->param_idx_w = 0;
+       hsw->param_idx_r = 0;
+       memset((void *)hsw->param_buf, 0, sizeof(hsw->param_buf));
+}
+
+int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf)
+{
+       /* save line to the first available position of param buffer */
+       if (hsw->param_idx_w > WAVES_PARAM_LINES - 1) {
+               dev_warn(hsw->dev, "warning: param buffer overflow!\n");
+               return -EPERM;
+       }
+       memcpy(hsw->param_buf[hsw->param_idx_w], buf, WAVES_PARAM_COUNT);
+       hsw->param_idx_w++;
+       return 0;
+}
+
+int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf)
+{
+       u8 id = 0;
+
+       /* read the first matching line from param buffer */
+       while (hsw->param_idx_r < WAVES_PARAM_LINES) {
+               id = hsw->param_buf[hsw->param_idx_r][0];
+               hsw->param_idx_r++;
+               if (buf[0] == id) {
+                       memcpy(buf, hsw->param_buf[hsw->param_idx_r],
+                               WAVES_PARAM_COUNT);
+                       break;
+               }
+       }
+       if (hsw->param_idx_r > WAVES_PARAM_LINES - 1) {
+               dev_dbg(hsw->dev, "end of buffer, roll to the beginning\n");
+               hsw->param_idx_r = 0;
+               return 0;
+       }
+       return 0;
+}
+
+int sst_hsw_launch_param_buf(struct sst_hsw *hsw)
+{
+       int ret, idx;
+
+       if (!sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) {
+               dev_dbg(hsw->dev, "module waves is not active\n");
+               return 0;
+       }
+
+       /* put all param lines to DSP through ipc */
+       for (idx = 0; idx < hsw->param_idx_w; idx++) {
+               ret = sst_hsw_module_set_param(hsw,
+                       SST_HSW_MODULE_WAVES, 0, hsw->param_buf[idx][0],
+                       WAVES_PARAM_COUNT, hsw->param_buf[idx]);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+int sst_hsw_module_load(struct sst_hsw *hsw,
+       u32 module_id, u32 instance_id, char *name)
+{
+       int ret = 0;
+       const struct firmware *fw = NULL;
+       struct sst_fw *hsw_sst_fw;
+       struct sst_module *module;
+       struct device *dev = hsw->dev;
+       struct sst_dsp *dsp = hsw->dsp;
+
+       dev_dbg(dev, "sst_hsw_module_load id=%d, name='%s'", module_id, name);
+
+       module = sst_module_get_from_id(dsp, module_id);
+       if (module == NULL) {
+               /* loading for the first time */
+               if (module_id == SST_HSW_MODULE_BASE_FW) {
+                       /* for base module: use fw requested in acpi probe */
+                       fw = dsp->pdata->fw;
+                       if (!fw) {
+                               dev_err(dev, "request Base fw failed\n");
+                               return -ENODEV;
+                       }
+               } else {
+                       /* try and load any other optional modules if they are
+                        * available. Use dev_info instead of dev_err in case
+                        * request firmware failed */
+                       ret = request_firmware(&fw, name, dev);
+                       if (ret) {
+                               dev_info(dev, "fw image %s not available(%d)\n",
+                                               name, ret);
+                               return ret;
+                       }
+               }
+               hsw_sst_fw = sst_fw_new(dsp, fw, hsw);
+               if (hsw_sst_fw  == NULL) {
+                       dev_err(dev, "error: failed to load firmware\n");
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               module = sst_module_get_from_id(dsp, module_id);
+               if (module == NULL) {
+                       dev_err(dev, "error: no module %d in firmware %s\n",
+                                       module_id, name);
+               }
+       } else
+               dev_info(dev, "module %d (%s) already loaded\n",
+                               module_id, name);
+out:
+       /* release fw, but base fw should be released by acpi driver */
+       if (fw && module_id != SST_HSW_MODULE_BASE_FW)
+               release_firmware(fw);
+
+       return ret;
+}
+
+int sst_hsw_module_enable(struct sst_hsw *hsw,
+       u32 module_id, u32 instance_id)
+{
+       int ret;
+       u32 header = 0;
+       struct sst_hsw_ipc_module_config config;
+       struct sst_module *module;
+       struct sst_module_runtime *runtime;
+       struct device *dev = hsw->dev;
+       struct sst_dsp *dsp = hsw->dsp;
+
+       if (!sst_hsw_is_module_loaded(hsw, module_id)) {
+               dev_dbg(dev, "module %d not loaded\n", module_id);
+               return 0;
+       }
+
+       if (sst_hsw_is_module_active(hsw, module_id)) {
+               dev_info(dev, "module %d already enabled\n", module_id);
+               return 0;
+       }
+
+       module = sst_module_get_from_id(dsp, module_id);
+       if (module == NULL) {
+               dev_err(dev, "module %d not valid\n", module_id);
+               return -ENXIO;
+       }
+
+       runtime = sst_module_runtime_get_from_id(module, module_id);
+       if (runtime == NULL) {
+               dev_err(dev, "runtime %d not valid", module_id);
+               return -ENXIO;
+       }
+
+       header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) |
+                       IPC_MODULE_OPERATION(IPC_MODULE_ENABLE) |
+                       IPC_MODULE_ID(module_id);
+       dev_dbg(dev, "module enable header: %x\n", header);
+
+       config.map.module_entries_count = 1;
+       config.map.module_entries[0].module_id = module->id;
+       config.map.module_entries[0].entry_point = module->entry;
+
+       config.persistent_mem.offset =
+               sst_dsp_get_offset(dsp,
+                       runtime->persistent_offset, SST_MEM_DRAM);
+       config.persistent_mem.size = module->persistent_size;
+
+       config.scratch_mem.offset =
+               sst_dsp_get_offset(dsp,
+                       dsp->scratch_offset, SST_MEM_DRAM);
+       config.scratch_mem.size = module->scratch_size;
+       dev_dbg(dev, "mod %d enable p:%d @ %x, s:%d @ %x, ep: %x",
+               config.map.module_entries[0].module_id,
+               config.persistent_mem.size,
+               config.persistent_mem.offset,
+               config.scratch_mem.size, config.scratch_mem.offset,
+               config.map.module_entries[0].entry_point);
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header,
+                       &config, sizeof(config), NULL, 0);
+       if (ret < 0)
+               dev_err(dev, "ipc: module enable failed - %d\n", ret);
+       else
+               module->state = SST_MODULE_STATE_ACTIVE;
+
+       return ret;
+}
+
+int sst_hsw_module_disable(struct sst_hsw *hsw,
+       u32 module_id, u32 instance_id)
+{
+       int ret;
+       u32 header;
+       struct sst_module *module;
+       struct device *dev = hsw->dev;
+       struct sst_dsp *dsp = hsw->dsp;
+
+       if (!sst_hsw_is_module_loaded(hsw, module_id)) {
+               dev_dbg(dev, "module %d not loaded\n", module_id);
+               return 0;
+       }
+
+       if (!sst_hsw_is_module_active(hsw, module_id)) {
+               dev_info(dev, "module %d already disabled\n", module_id);
+               return 0;
+       }
+
+       module = sst_module_get_from_id(dsp, module_id);
+       if (module == NULL) {
+               dev_err(dev, "module %d not valid\n", module_id);
+               return -ENXIO;
+       }
+
+       header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) |
+                       IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) |
+                       IPC_MODULE_ID(module_id);
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header,  NULL, 0, NULL, 0);
+       if (ret < 0)
+               dev_err(dev, "module disable failed - %d\n", ret);
+       else
+               module->state = SST_MODULE_STATE_INITIALIZED;
+
+       return ret;
+}
+
+int sst_hsw_module_set_param(struct sst_hsw *hsw,
+       u32 module_id, u32 instance_id, u32 parameter_id,
+       u32 param_size, char *param)
+{
+       int ret;
+       unsigned char *data = NULL;
+       u32 header = 0;
+       u32 payload_size = 0, transfer_parameter_size = 0;
+       dma_addr_t dma_addr = 0;
+       struct sst_hsw_transfer_parameter *parameter;
+       struct device *dev = hsw->dev;
+
+       header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) |
+                       IPC_MODULE_OPERATION(IPC_MODULE_SET_PARAMETER) |
+                       IPC_MODULE_ID(module_id);
+       dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", header);
+
+       payload_size = param_size +
+               sizeof(struct sst_hsw_transfer_parameter) -
+               sizeof(struct sst_hsw_transfer_list);
+       dev_dbg(dev, "parameter size : %d\n", param_size);
+       dev_dbg(dev, "payload size   : %d\n", payload_size);
+
+       if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) {
+               /* short parameter, mailbox can contain data */
+               dev_dbg(dev, "transfer parameter size : %d\n",
+                       transfer_parameter_size);
+
+               transfer_parameter_size = ALIGN(payload_size, 4);
+               dev_dbg(dev, "transfer parameter aligned size : %d\n",
+                       transfer_parameter_size);
+
+               parameter = kzalloc(transfer_parameter_size, GFP_KERNEL);
+               if (parameter == NULL)
+                       return -ENOMEM;
+
+               memcpy(parameter->data, param, param_size);
+       } else {
+               dev_warn(dev, "transfer parameter size too large!");
+               return 0;
+       }
+
+       parameter->parameter_id = parameter_id;
+       parameter->data_size = param_size;
+
+       ret = sst_ipc_tx_message_wait(&hsw->ipc, header,
+               parameter, transfer_parameter_size , NULL, 0);
+       if (ret < 0)
+               dev_err(dev, "ipc: module set parameter failed - %d\n", ret);
+
+       kfree(parameter);
+
+       if (data)
+               dma_free_coherent(hsw->dsp->dma_dev,
+                       param_size, (void *)data, dma_addr);
+
+       return ret;
+}
+
+static struct sst_dsp_device hsw_dev = {
+       .thread = hsw_irq_thread,
+       .ops = &haswell_ops,
+};
+
+static void hsw_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
+{
+       /* send the message */
+       sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
+       sst_dsp_ipc_msg_tx(ipc->dsp, msg->header);
+}
+
+static void hsw_shim_dbg(struct sst_generic_ipc *ipc, const char *text)
+{
+       struct sst_dsp *sst = ipc->dsp;
+       u32 isr, ipcd, imrx, ipcx;
+
+       ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX);
+       isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
+       ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+       imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX);
+
+       dev_err(ipc->dev,
+               "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n",
+               text, ipcx, isr, ipcd, imrx);
+}
+
+static void hsw_tx_data_copy(struct ipc_message *msg, char *tx_data,
+       size_t tx_size)
+{
+       memcpy(msg->tx_data, tx_data, tx_size);
+}
+
+static u64 hsw_reply_msg_match(u64 header, u64 *mask)
+{
+       /* clear reply bits & status bits */
+       header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
+       *mask = (u64)-1;
+
+       return header;
+}
+
+int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_hsw_ipc_fw_version version;
+       struct sst_hsw *hsw;
+       struct sst_generic_ipc *ipc;
+       int ret;
+
+       dev_dbg(dev, "initialising Audio DSP IPC\n");
+
+       hsw = devm_kzalloc(dev, sizeof(*hsw), GFP_KERNEL);
+       if (hsw == NULL)
+               return -ENOMEM;
+
+       ipc = &hsw->ipc;
+       ipc->dev = dev;
+       ipc->ops.tx_msg = hsw_tx_msg;
+       ipc->ops.shim_dbg = hsw_shim_dbg;
+       ipc->ops.tx_data_copy = hsw_tx_data_copy;
+       ipc->ops.reply_msg_match = hsw_reply_msg_match;
+
+       ret = sst_ipc_init(ipc);
+       if (ret != 0)
+               goto ipc_init_err;
+
+       INIT_LIST_HEAD(&hsw->stream_list);
+       init_waitqueue_head(&hsw->boot_wait);
+       hsw_dev.thread_context = hsw;
+
+       /* init SST shim */
+       hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata);
+       if (hsw->dsp == NULL) {
+               ret = -ENODEV;
+               goto dsp_new_err;
+       }
+
+       ipc->dsp = hsw->dsp;
+
+       /* allocate DMA buffer for context storage */
+       hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev,
+               SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL);
+       if (hsw->dx_context == NULL) {
+               ret = -ENOMEM;
+               goto dma_err;
+       }
+
+       /* keep the DSP in reset state for base FW loading */
+       sst_dsp_reset(hsw->dsp);
+
+       /* load base module and other modules in base firmware image */
+       ret = sst_hsw_module_load(hsw, SST_HSW_MODULE_BASE_FW, 0, "Base");
+       if (ret < 0)
+               goto fw_err;
+
+       /* try to load module waves */
+       sst_hsw_module_load(hsw, SST_HSW_MODULE_WAVES, 0, "intel/IntcPP01.bin");
+
+       /* allocate scratch mem regions */
+       ret = sst_block_alloc_scratch(hsw->dsp);
+       if (ret < 0)
+               goto boot_err;
+
+       /* init param buffer */
+       sst_hsw_reset_param_buf(hsw);
+
+       /* wait for DSP boot completion */
+       sst_dsp_boot(hsw->dsp);
+       ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
+               msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (ret == 0) {
+               ret = -EIO;
+               dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n",
+                       sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD),
+                       sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX));
+               goto boot_err;
+       }
+
+       /* init module state after boot */
+       sst_hsw_init_module_state(hsw);
+
+       /* get the FW version */
+       sst_hsw_fw_get_version(hsw, &version);
+
+       /* get the globalmixer */
+       ret = sst_hsw_mixer_get_info(hsw);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: failed to get stream info\n");
+               goto boot_err;
+       }
+
+       pdata->dsp = hsw;
+       return 0;
+
+boot_err:
+       sst_dsp_reset(hsw->dsp);
+       sst_fw_free_all(hsw->dsp);
+fw_err:
+       dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
+                       hsw->dx_context, hsw->dx_context_paddr);
+dma_err:
+       sst_dsp_free(hsw->dsp);
+dsp_new_err:
+       sst_ipc_fini(ipc);
+ipc_init_err:
+       kfree(hsw);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_hsw_dsp_init);
+
+void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_hsw *hsw = pdata->dsp;
+
+       sst_dsp_reset(hsw->dsp);
+       sst_fw_free_all(hsw->dsp);
+       dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
+                       hsw->dx_context, hsw->dx_context_paddr);
+       sst_dsp_free(hsw->dsp);
+       sst_ipc_fini(&hsw->ipc);
+}
+EXPORT_SYMBOL_GPL(sst_hsw_dsp_free);
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.h b/sound/soc/intel/haswell/sst-haswell-ipc.h
new file mode 100644 (file)
index 0000000..06d71ae
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Intel SST Haswell/Broadwell IPC Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SST_HASWELL_IPC_H
+#define __SST_HASWELL_IPC_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <sound/asound.h>
+
+#define SST_HSW_NO_CHANNELS            4
+#define SST_HSW_MAX_DX_REGIONS         14
+#define SST_HSW_DX_CONTEXT_SIZE        (640 * 1024)
+#define SST_HSW_CHANNELS_ALL           0xffffffff
+
+#define SST_HSW_FW_LOG_CONFIG_DWORDS   12
+#define SST_HSW_GLOBAL_LOG             15
+
+/**
+ * Upfront defined maximum message size that is
+ * expected by the in/out communication pipes in FW.
+ */
+#define SST_HSW_IPC_MAX_PAYLOAD_SIZE   400
+#define SST_HSW_MAX_INFO_SIZE          64
+#define SST_HSW_BUILD_HASH_LENGTH      40
+#define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE   500
+#define WAVES_PARAM_COUNT              128
+#define WAVES_PARAM_LINES              160
+
+struct sst_hsw;
+struct sst_hsw_stream;
+struct sst_hsw_log_stream;
+struct sst_pdata;
+struct sst_module;
+struct sst_module_runtime;
+extern struct sst_ops haswell_ops;
+
+/* Stream Allocate Path ID */
+enum sst_hsw_stream_path_id {
+       SST_HSW_STREAM_PATH_SSP0_OUT = 0,
+       SST_HSW_STREAM_PATH_SSP0_IN = 1,
+       SST_HSW_STREAM_PATH_MAX_PATH_ID = 2,
+};
+
+/* Stream Allocate Stream Type */
+enum sst_hsw_stream_type {
+       SST_HSW_STREAM_TYPE_RENDER = 0,
+       SST_HSW_STREAM_TYPE_SYSTEM = 1,
+       SST_HSW_STREAM_TYPE_CAPTURE = 2,
+       SST_HSW_STREAM_TYPE_LOOPBACK = 3,
+       SST_HSW_STREAM_TYPE_MAX_STREAM_TYPE = 4,
+};
+
+/* Stream Allocate Stream Format */
+enum sst_hsw_stream_format {
+       SST_HSW_STREAM_FORMAT_PCM_FORMAT = 0,
+       SST_HSW_STREAM_FORMAT_MP3_FORMAT = 1,
+       SST_HSW_STREAM_FORMAT_AAC_FORMAT = 2,
+       SST_HSW_STREAM_FORMAT_MAX_FORMAT_ID = 3,
+};
+
+/* Device ID */
+enum sst_hsw_device_id {
+       SST_HSW_DEVICE_SSP_0   = 0,
+       SST_HSW_DEVICE_SSP_1   = 1,
+};
+
+/* Device Master Clock Frequency */
+enum sst_hsw_device_mclk {
+       SST_HSW_DEVICE_MCLK_OFF         = 0,
+       SST_HSW_DEVICE_MCLK_FREQ_6_MHZ  = 1,
+       SST_HSW_DEVICE_MCLK_FREQ_12_MHZ = 2,
+       SST_HSW_DEVICE_MCLK_FREQ_24_MHZ = 3,
+};
+
+/* Device Clock Master */
+enum sst_hsw_device_mode {
+       SST_HSW_DEVICE_CLOCK_SLAVE   = 0,
+       SST_HSW_DEVICE_CLOCK_MASTER  = 1,
+       SST_HSW_DEVICE_TDM_CLOCK_MASTER = 2,
+};
+
+/* DX Power State */
+enum sst_hsw_dx_state {
+       SST_HSW_DX_STATE_D0     = 0,
+       SST_HSW_DX_STATE_D1     = 1,
+       SST_HSW_DX_STATE_D3     = 3,
+       SST_HSW_DX_STATE_MAX    = 3,
+};
+
+/* Audio stream stage IDs */
+enum sst_hsw_fx_stage_id {
+       SST_HSW_STAGE_ID_WAVES = 0,
+       SST_HSW_STAGE_ID_DTS   = 1,
+       SST_HSW_STAGE_ID_DOLBY = 2,
+       SST_HSW_STAGE_ID_BOOST = 3,
+       SST_HSW_STAGE_ID_MAX_FX_ID
+};
+
+/* DX State Type */
+enum sst_hsw_dx_type {
+       SST_HSW_DX_TYPE_FW_IMAGE = 0,
+       SST_HSW_DX_TYPE_MEMORY_DUMP = 1
+};
+
+/* Volume Curve Type*/
+enum sst_hsw_volume_curve {
+       SST_HSW_VOLUME_CURVE_NONE = 0,
+       SST_HSW_VOLUME_CURVE_FADE = 1
+};
+
+/* Sample ordering */
+enum sst_hsw_interleaving {
+       SST_HSW_INTERLEAVING_PER_CHANNEL = 0,
+       SST_HSW_INTERLEAVING_PER_SAMPLE  = 1,
+};
+
+/* Channel indices */
+enum sst_hsw_channel_index {
+       SST_HSW_CHANNEL_LEFT            = 0,
+       SST_HSW_CHANNEL_CENTER          = 1,
+       SST_HSW_CHANNEL_RIGHT           = 2,
+       SST_HSW_CHANNEL_LEFT_SURROUND   = 3,
+       SST_HSW_CHANNEL_CENTER_SURROUND = 3,
+       SST_HSW_CHANNEL_RIGHT_SURROUND  = 4,
+       SST_HSW_CHANNEL_LFE             = 7,
+       SST_HSW_CHANNEL_INVALID         = 0xF,
+};
+
+/* List of supported channel maps. */
+enum sst_hsw_channel_config {
+       SST_HSW_CHANNEL_CONFIG_MONO      = 0, /* mono only. */
+       SST_HSW_CHANNEL_CONFIG_STEREO    = 1, /* L & R. */
+       SST_HSW_CHANNEL_CONFIG_2_POINT_1 = 2, /* L, R & LFE; PCM only. */
+       SST_HSW_CHANNEL_CONFIG_3_POINT_0 = 3, /* L, C & R; MP3 & AAC only. */
+       SST_HSW_CHANNEL_CONFIG_3_POINT_1 = 4, /* L, C, R & LFE; PCM only. */
+       SST_HSW_CHANNEL_CONFIG_QUATRO    = 5, /* L, R, Ls & Rs; PCM only. */
+       SST_HSW_CHANNEL_CONFIG_4_POINT_0 = 6, /* L, C, R & Cs; MP3 & AAC only. */
+       SST_HSW_CHANNEL_CONFIG_5_POINT_0 = 7, /* L, C, R, Ls & Rs. */
+       SST_HSW_CHANNEL_CONFIG_5_POINT_1 = 8, /* L, C, R, Ls, Rs & LFE. */
+       SST_HSW_CHANNEL_CONFIG_DUAL_MONO = 9, /* One channel replicated in two. */
+       SST_HSW_CHANNEL_CONFIG_INVALID,
+};
+
+/* List of supported bit depths. */
+enum sst_hsw_bitdepth {
+       SST_HSW_DEPTH_8BIT  = 8,
+       SST_HSW_DEPTH_16BIT = 16,
+       SST_HSW_DEPTH_24BIT = 24, /* Default. */
+       SST_HSW_DEPTH_32BIT = 32,
+       SST_HSW_DEPTH_INVALID = 33,
+};
+
+enum sst_hsw_module_id {
+       SST_HSW_MODULE_BASE_FW = 0x0,
+       SST_HSW_MODULE_MP3     = 0x1,
+       SST_HSW_MODULE_AAC_5_1 = 0x2,
+       SST_HSW_MODULE_AAC_2_0 = 0x3,
+       SST_HSW_MODULE_SRC     = 0x4,
+       SST_HSW_MODULE_WAVES   = 0x5,
+       SST_HSW_MODULE_DOLBY   = 0x6,
+       SST_HSW_MODULE_BOOST   = 0x7,
+       SST_HSW_MODULE_LPAL    = 0x8,
+       SST_HSW_MODULE_DTS     = 0x9,
+       SST_HSW_MODULE_PCM_CAPTURE = 0xA,
+       SST_HSW_MODULE_PCM_SYSTEM = 0xB,
+       SST_HSW_MODULE_PCM_REFERENCE = 0xC,
+       SST_HSW_MODULE_PCM = 0xD,
+       SST_HSW_MODULE_BLUETOOTH_RENDER_MODULE = 0xE,
+       SST_HSW_MODULE_BLUETOOTH_CAPTURE_MODULE = 0xF,
+       SST_HSW_MAX_MODULE_ID,
+};
+
+enum sst_hsw_performance_action {
+       SST_HSW_PERF_START = 0,
+       SST_HSW_PERF_STOP = 1,
+};
+
+struct sst_hsw_transfer_info {
+       uint32_t destination;       /* destination address */
+       uint32_t reverse:1;         /* if 1 data flows from destination */
+       uint32_t size:31;           /* transfer size in bytes.*/
+       uint16_t first_page_offset; /* offset to data in the first page. */
+       uint8_t  packed_pages;   /* page addresses. Each occupies 20 bits */
+} __attribute__((packed));
+
+struct sst_hsw_transfer_list {
+       uint32_t transfers_count;
+       struct sst_hsw_transfer_info transfers;
+} __attribute__((packed));
+
+struct sst_hsw_transfer_parameter {
+       uint32_t parameter_id;
+       uint32_t data_size;
+       union {
+               uint8_t data[1];
+               struct sst_hsw_transfer_list transfer_list;
+       };
+} __attribute__((packed));
+
+/* SST firmware module info */
+struct sst_hsw_module_info {
+       u8 name[SST_HSW_MAX_INFO_SIZE];
+       u8 version[SST_HSW_MAX_INFO_SIZE];
+} __attribute__((packed));
+
+/* Module entry point */
+struct sst_hsw_module_entry {
+       enum sst_hsw_module_id module_id;
+       u32 entry_point;
+} __attribute__((packed));
+
+/* Module map - alignement matches DSP */
+struct sst_hsw_module_map {
+       u8 module_entries_count;
+       struct sst_hsw_module_entry module_entries[1];
+} __attribute__((packed));
+
+struct sst_hsw_memory_info {
+       u32 offset;
+       u32 size;
+} __attribute__((packed));
+
+struct sst_hsw_fx_enable {
+       struct sst_hsw_module_map module_map;
+       struct sst_hsw_memory_info persistent_mem;
+} __attribute__((packed));
+
+struct sst_hsw_ipc_module_config {
+       struct sst_hsw_module_map map;
+       struct sst_hsw_memory_info persistent_mem;
+       struct sst_hsw_memory_info scratch_mem;
+} __attribute__((packed));
+
+struct sst_hsw_get_fx_param {
+       u32 parameter_id;
+       u32 param_size;
+} __attribute__((packed));
+
+struct sst_hsw_perf_action {
+       u32 action;
+} __attribute__((packed));
+
+struct sst_hsw_perf_data {
+       u64 timestamp;
+       u64 cycles;
+       u64 datatime;
+} __attribute__((packed));
+
+/* FW version */
+struct sst_hsw_ipc_fw_version {
+       u8 build;
+       u8 minor;
+       u8 major;
+       u8 type;
+       u8 fw_build_hash[SST_HSW_BUILD_HASH_LENGTH];
+       u32 fw_log_providers_hash;
+} __attribute__((packed));
+
+/* Stream ring info */
+struct sst_hsw_ipc_stream_ring {
+       u32 ring_pt_address;
+       u32 num_pages;
+       u32 ring_size;
+       u32 ring_offset;
+       u32 ring_first_pfn;
+} __attribute__((packed));
+
+/* Debug Dump Log Enable Request */
+struct sst_hsw_ipc_debug_log_enable_req {
+       struct sst_hsw_ipc_stream_ring ringinfo;
+       u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
+} __attribute__((packed));
+
+/* Debug Dump Log Reply */
+struct sst_hsw_ipc_debug_log_reply {
+       u32 log_buffer_begining;
+       u32 log_buffer_size;
+} __attribute__((packed));
+
+/* Stream glitch position */
+struct sst_hsw_ipc_stream_glitch_position {
+       u32 glitch_type;
+       u32 present_pos;
+       u32 write_pos;
+} __attribute__((packed));
+
+/* Stream get position */
+struct sst_hsw_ipc_stream_get_position {
+       u32 position;
+       u32 fw_cycle_count;
+} __attribute__((packed));
+
+/* Stream set position */
+struct sst_hsw_ipc_stream_set_position {
+       u32 position;
+       u32 end_of_buffer;
+} __attribute__((packed));
+
+/* Stream Free Request */
+struct sst_hsw_ipc_stream_free_req {
+       u8 stream_id;
+       u8 reserved[3];
+} __attribute__((packed));
+
+/* Set Volume Request */
+struct sst_hsw_ipc_volume_req {
+       u32 channel;
+       u32 target_volume;
+       u64 curve_duration;
+       u32 curve_type;
+} __attribute__((packed));
+
+/* Device Configuration Request */
+struct sst_hsw_ipc_device_config_req {
+       u32 ssp_interface;
+       u32 clock_frequency;
+       u32 mode;
+       u16 clock_divider;
+       u8 channels;
+       u8 reserved;
+} __attribute__((packed));
+
+/* Audio Data formats */
+struct sst_hsw_audio_data_format_ipc {
+       u32 frequency;
+       u32 bitdepth;
+       u32 map;
+       u32 config;
+       u32 style;
+       u8 ch_num;
+       u8 valid_bit;
+       u8 reserved[2];
+} __attribute__((packed));
+
+/* Stream Allocate Request */
+struct sst_hsw_ipc_stream_alloc_req {
+       u8 path_id;
+       u8 stream_type;
+       u8 format_id;
+       u8 reserved;
+       struct sst_hsw_audio_data_format_ipc format;
+       struct sst_hsw_ipc_stream_ring ringinfo;
+       struct sst_hsw_module_map map;
+       struct sst_hsw_memory_info persistent_mem;
+       struct sst_hsw_memory_info scratch_mem;
+       u32 number_of_notifications;
+} __attribute__((packed));
+
+/* Stream Allocate Reply */
+struct sst_hsw_ipc_stream_alloc_reply {
+       u32 stream_hw_id;
+       u32 mixer_hw_id; // returns rate ????
+       u32 read_position_register_address;
+       u32 presentation_position_register_address;
+       u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
+       u32 volume_register_address[SST_HSW_NO_CHANNELS];
+} __attribute__((packed));
+
+/* Get Mixer Stream Info */
+struct sst_hsw_ipc_stream_info_reply {
+       u32 mixer_hw_id;
+       u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
+       u32 volume_register_address[SST_HSW_NO_CHANNELS];
+} __attribute__((packed));
+
+/* DX State Request */
+struct sst_hsw_ipc_dx_req {
+       u8 state;
+       u8 reserved[3];
+} __attribute__((packed));
+
+/* DX State Reply Memory Info Item */
+struct sst_hsw_ipc_dx_memory_item {
+       u32 offset;
+       u32 size;
+       u32 source;
+} __attribute__((packed));
+
+/* DX State Reply */
+struct sst_hsw_ipc_dx_reply {
+       u32 entries_no;
+       struct sst_hsw_ipc_dx_memory_item mem_info[SST_HSW_MAX_DX_REGIONS];
+} __attribute__((packed));
+
+struct sst_hsw_ipc_fw_version;
+
+/* SST Init & Free */
+struct sst_hsw *sst_hsw_new(struct device *dev, const u8 *fw, size_t fw_length,
+       u32 fw_offset);
+void sst_hsw_free(struct sst_hsw *hsw);
+int sst_hsw_fw_get_version(struct sst_hsw *hsw,
+       struct sst_hsw_ipc_fw_version *version);
+u32 create_channel_map(enum sst_hsw_channel_config config);
+
+/* Stream Mixer Controls - */
+int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume);
+int sst_hsw_stream_get_volume(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume);
+
+/* Global Mixer Controls - */
+int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+       u32 volume);
+int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+       u32 *volume);
+
+/* Stream API */
+struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
+       u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data),
+       void *data);
+
+int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+/* Stream Configuration */
+int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       enum sst_hsw_stream_path_id path_id,
+       enum sst_hsw_stream_type stream_type,
+       enum sst_hsw_stream_format format_id);
+
+int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 ring_pt_address, u32 num_pages,
+       u32 ring_size, u32 ring_offset, u32 ring_first_pfn);
+
+int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+int sst_hsw_stream_set_valid(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 bits);
+int sst_hsw_stream_set_rate(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int rate);
+int sst_hsw_stream_set_bits(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       enum sst_hsw_bitdepth bits);
+int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, int channels);
+int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 map,
+       enum sst_hsw_channel_config config);
+int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       enum sst_hsw_interleaving style);
+int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, struct sst_module_runtime *runtime);
+int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 offset, u32 size);
+int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 offset, u32 size);
+snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, snd_pcm_uframes_t val);
+bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, bool val);
+int sst_hsw_mixer_get_info(struct sst_hsw *hsw);
+
+/* Stream ALSA trigger operations */
+int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int wait);
+int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int wait);
+int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+/* Stream pointer positions */
+int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 *position);
+int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 *position);
+u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+
+/* HW port config */
+int sst_hsw_device_set_config(struct sst_hsw *hsw,
+       enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
+       enum sst_hsw_device_mode mode, u32 clock_divider);
+
+/* DX Config */
+int sst_hsw_dx_set_state(struct sst_hsw *hsw,
+       enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx);
+
+/* init */
+int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);
+void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata);
+struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
+
+/* fw module function */
+void sst_hsw_init_module_state(struct sst_hsw *hsw);
+bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id);
+bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id);
+void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id);
+void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id);
+bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id);
+void sst_hsw_reset_param_buf(struct sst_hsw *hsw);
+int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf);
+int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf);
+int sst_hsw_launch_param_buf(struct sst_hsw *hsw);
+
+int sst_hsw_module_load(struct sst_hsw *hsw,
+       u32 module_id, u32 instance_id, char *name);
+int sst_hsw_module_enable(struct sst_hsw *hsw,
+       u32 module_id, u32 instance_id);
+int sst_hsw_module_disable(struct sst_hsw *hsw,
+       u32 module_id, u32 instance_id);
+int sst_hsw_module_set_param(struct sst_hsw *hsw,
+       u32 module_id, u32 instance_id, u32 parameter_id,
+       u32 param_size, char *param);
+
+/* runtime module management */
+struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
+       int mod_id, int offset);
+void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime);
+
+/* PM */
+int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw);
+int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw);
+int sst_hsw_dsp_load(struct sst_hsw *hsw);
+int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw);
+
+#endif
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c
new file mode 100644 (file)
index 0000000..23ae040
--- /dev/null
@@ -0,0 +1,1405 @@
+/*
+ * Intel SST Haswell/Broadwell PCM Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/compress_driver.h>
+
+#include "../haswell/sst-haswell-ipc.h"
+#include "../common/sst-dsp-priv.h"
+#include "../common/sst-dsp.h"
+
+#define HSW_PCM_COUNT          6
+#define HSW_VOLUME_MAX         0x7FFFFFFF      /* 0dB */
+
+#define SST_OLD_POSITION(d, r, o) ((d) +               \
+                       frames_to_bytes(r, o))
+#define SST_SAMPLES(r, x) (bytes_to_samples(r, \
+                       frames_to_bytes(r, (x))))
+
+/* simple volume table */
+static const u32 volume_map[] = {
+       HSW_VOLUME_MAX >> 30,
+       HSW_VOLUME_MAX >> 29,
+       HSW_VOLUME_MAX >> 28,
+       HSW_VOLUME_MAX >> 27,
+       HSW_VOLUME_MAX >> 26,
+       HSW_VOLUME_MAX >> 25,
+       HSW_VOLUME_MAX >> 24,
+       HSW_VOLUME_MAX >> 23,
+       HSW_VOLUME_MAX >> 22,
+       HSW_VOLUME_MAX >> 21,
+       HSW_VOLUME_MAX >> 20,
+       HSW_VOLUME_MAX >> 19,
+       HSW_VOLUME_MAX >> 18,
+       HSW_VOLUME_MAX >> 17,
+       HSW_VOLUME_MAX >> 16,
+       HSW_VOLUME_MAX >> 15,
+       HSW_VOLUME_MAX >> 14,
+       HSW_VOLUME_MAX >> 13,
+       HSW_VOLUME_MAX >> 12,
+       HSW_VOLUME_MAX >> 11,
+       HSW_VOLUME_MAX >> 10,
+       HSW_VOLUME_MAX >> 9,
+       HSW_VOLUME_MAX >> 8,
+       HSW_VOLUME_MAX >> 7,
+       HSW_VOLUME_MAX >> 6,
+       HSW_VOLUME_MAX >> 5,
+       HSW_VOLUME_MAX >> 4,
+       HSW_VOLUME_MAX >> 3,
+       HSW_VOLUME_MAX >> 2,
+       HSW_VOLUME_MAX >> 1,
+       HSW_VOLUME_MAX >> 0,
+};
+
+#define HSW_PCM_PERIODS_MAX    64
+#define HSW_PCM_PERIODS_MIN    2
+
+#define HSW_PCM_DAI_ID_SYSTEM  0
+#define HSW_PCM_DAI_ID_OFFLOAD0        1
+#define HSW_PCM_DAI_ID_OFFLOAD1        2
+#define HSW_PCM_DAI_ID_LOOPBACK        3
+
+
+static const struct snd_pcm_hardware hsw_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+                                 SNDRV_PCM_INFO_DRAIN_TRIGGER,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+                                 SNDRV_PCM_FMTBIT_S32_LE,
+       .period_bytes_min       = PAGE_SIZE,
+       .period_bytes_max       = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE,
+       .periods_min            = HSW_PCM_PERIODS_MIN,
+       .periods_max            = HSW_PCM_PERIODS_MAX,
+       .buffer_bytes_max       = HSW_PCM_PERIODS_MAX * PAGE_SIZE,
+};
+
+struct hsw_pcm_module_map {
+       int dai_id;
+       int stream;
+       enum sst_hsw_module_id mod_id;
+};
+
+/* private data for each PCM DSP stream */
+struct hsw_pcm_data {
+       int dai_id;
+       struct sst_hsw_stream *stream;
+       struct sst_module_runtime *runtime;
+       struct sst_module_runtime_context context;
+       struct snd_pcm *hsw_pcm;
+       u32 volume[2];
+       struct snd_pcm_substream *substream;
+       struct snd_compr_stream *cstream;
+       unsigned int wpos;
+       struct mutex mutex;
+       bool allocated;
+       int persistent_offset;
+};
+
+enum hsw_pm_state {
+       HSW_PM_STATE_D0 = 0,
+       HSW_PM_STATE_RTD3 = 1,
+       HSW_PM_STATE_D3 = 2,
+};
+
+/* private data for the driver */
+struct hsw_priv_data {
+       /* runtime DSP */
+       struct sst_hsw *hsw;
+       struct device *dev;
+       enum hsw_pm_state pm_state;
+       struct snd_soc_card *soc_card;
+       struct sst_module_runtime *runtime_waves; /* sound effect module */
+
+       /* page tables */
+       struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
+
+       /* DAI data */
+       struct hsw_pcm_data pcm[HSW_PCM_COUNT][2];
+};
+
+
+/* static mappings between PCMs and modules - may be dynamic in future */
+static struct hsw_pcm_module_map mod_map[] = {
+       {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM},
+       {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM},
+       {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM},
+       {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE},
+       {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE},
+};
+
+static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
+
+static inline u32 hsw_mixer_to_ipc(unsigned int value)
+{
+       if (value >= ARRAY_SIZE(volume_map))
+               return volume_map[0];
+       else
+               return volume_map[value];
+}
+
+static inline unsigned int hsw_ipc_to_mixer(u32 value)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(volume_map); i++) {
+               if (volume_map[i] >= value)
+                       return i;
+       }
+
+       return i - 1;
+}
+
+static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(platform);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw *hsw = pdata->hsw;
+       u32 volume;
+       int dai, stream;
+
+       dai = mod_map[mc->reg].dai_id;
+       stream = mod_map[mc->reg].stream;
+       pcm_data = &pdata->pcm[dai][stream];
+
+       mutex_lock(&pcm_data->mutex);
+       pm_runtime_get_sync(pdata->dev);
+
+       if (!pcm_data->stream) {
+               pcm_data->volume[0] =
+                       hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               pcm_data->volume[1] =
+                       hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+               pm_runtime_mark_last_busy(pdata->dev);
+               pm_runtime_put_autosuspend(pdata->dev);
+               mutex_unlock(&pcm_data->mutex);
+               return 0;
+       }
+
+       if (ucontrol->value.integer.value[0] ==
+               ucontrol->value.integer.value[1]) {
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               /* apply volume value to all channels */
+               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, SST_HSW_CHANNELS_ALL, volume);
+       } else {
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume);
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume);
+       }
+
+       pm_runtime_mark_last_busy(pdata->dev);
+       pm_runtime_put_autosuspend(pdata->dev);
+       mutex_unlock(&pcm_data->mutex);
+       return 0;
+}
+
+static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(platform);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw *hsw = pdata->hsw;
+       u32 volume;
+       int dai, stream;
+
+       dai = mod_map[mc->reg].dai_id;
+       stream = mod_map[mc->reg].stream;
+       pcm_data = &pdata->pcm[dai][stream];
+
+       mutex_lock(&pcm_data->mutex);
+       pm_runtime_get_sync(pdata->dev);
+
+       if (!pcm_data->stream) {
+               ucontrol->value.integer.value[0] =
+                       hsw_ipc_to_mixer(pcm_data->volume[0]);
+               ucontrol->value.integer.value[1] =
+                       hsw_ipc_to_mixer(pcm_data->volume[1]);
+               pm_runtime_mark_last_busy(pdata->dev);
+               pm_runtime_put_autosuspend(pdata->dev);
+               mutex_unlock(&pcm_data->mutex);
+               return 0;
+       }
+
+       sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 0, &volume);
+       ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
+       sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume);
+       ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
+
+       pm_runtime_mark_last_busy(pdata->dev);
+       pm_runtime_put_autosuspend(pdata->dev);
+       mutex_unlock(&pcm_data->mutex);
+
+       return 0;
+}
+
+static int hsw_volume_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct sst_hsw *hsw = pdata->hsw;
+       u32 volume;
+
+       pm_runtime_get_sync(pdata->dev);
+
+       if (ucontrol->value.integer.value[0] ==
+               ucontrol->value.integer.value[1]) {
+
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               sst_hsw_mixer_set_volume(hsw, 0, SST_HSW_CHANNELS_ALL, volume);
+
+       } else {
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               sst_hsw_mixer_set_volume(hsw, 0, 0, volume);
+
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+               sst_hsw_mixer_set_volume(hsw, 0, 1, volume);
+       }
+
+       pm_runtime_mark_last_busy(pdata->dev);
+       pm_runtime_put_autosuspend(pdata->dev);
+       return 0;
+}
+
+static int hsw_volume_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct sst_hsw *hsw = pdata->hsw;
+       unsigned int volume = 0;
+
+       pm_runtime_get_sync(pdata->dev);
+       sst_hsw_mixer_get_volume(hsw, 0, 0, &volume);
+       ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
+
+       sst_hsw_mixer_get_volume(hsw, 0, 1, &volume);
+       ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
+
+       pm_runtime_mark_last_busy(pdata->dev);
+       pm_runtime_put_autosuspend(pdata->dev);
+       return 0;
+}
+
+static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct sst_hsw *hsw = pdata->hsw;
+       enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
+
+       ucontrol->value.integer.value[0] =
+               (sst_hsw_is_module_active(hsw, id) ||
+               sst_hsw_is_module_enabled_rtd3(hsw, id));
+       return 0;
+}
+
+static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct sst_hsw *hsw = pdata->hsw;
+       int ret = 0;
+       enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
+       bool switch_on = (bool)ucontrol->value.integer.value[0];
+
+       /* if module is in RAM on the DSP, apply user settings to module through
+        * ipc. If module is not in RAM on the DSP, store user setting for
+        * track */
+       if (sst_hsw_is_module_loaded(hsw, id)) {
+               if (switch_on == sst_hsw_is_module_active(hsw, id))
+                       return 0;
+
+               if (switch_on)
+                       ret = sst_hsw_module_enable(hsw, id, 0);
+               else
+                       ret = sst_hsw_module_disable(hsw, id, 0);
+       } else {
+               if (switch_on == sst_hsw_is_module_enabled_rtd3(hsw, id))
+                       return 0;
+
+               if (switch_on)
+                       sst_hsw_set_module_enabled_rtd3(hsw, id);
+               else
+                       sst_hsw_set_module_disabled_rtd3(hsw, id);
+       }
+
+       return ret;
+}
+
+static int hsw_waves_param_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct sst_hsw *hsw = pdata->hsw;
+
+       /* return a matching line from param buffer */
+       return sst_hsw_load_param_line(hsw, ucontrol->value.bytes.data);
+}
+
+static int hsw_waves_param_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct sst_hsw *hsw = pdata->hsw;
+       int ret;
+       enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
+       int param_id = ucontrol->value.bytes.data[0];
+       int param_size = WAVES_PARAM_COUNT;
+
+       /* clear param buffer and reset buffer index */
+       if (param_id == 0xFF) {
+               sst_hsw_reset_param_buf(hsw);
+               return 0;
+       }
+
+       /* store params into buffer */
+       ret = sst_hsw_store_param_line(hsw, ucontrol->value.bytes.data);
+       if (ret < 0)
+               return ret;
+
+       if (sst_hsw_is_module_active(hsw, id))
+               ret = sst_hsw_module_set_param(hsw, id, 0, param_id,
+                               param_size, ucontrol->value.bytes.data);
+       return ret;
+}
+
+/* TLV used by both global and stream volumes */
+static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
+
+/* System Pin has no volume control */
+static const struct snd_kcontrol_new hsw_volume_controls[] = {
+       /* Global DSP volume */
+       SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8,
+               ARRAY_SIZE(volume_map) - 1, 0,
+               hsw_volume_get, hsw_volume_put, hsw_vol_tlv),
+       /* Offload 0 volume */
+       SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8,
+               ARRAY_SIZE(volume_map) - 1, 0,
+               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+       /* Offload 1 volume */
+       SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8,
+               ARRAY_SIZE(volume_map) - 1, 0,
+               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+       /* Mic Capture volume */
+       SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
+               ARRAY_SIZE(volume_map) - 1, 0,
+               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+       /* enable/disable module waves */
+       SOC_SINGLE_BOOL_EXT("Waves Switch", 0,
+               hsw_waves_switch_get, hsw_waves_switch_put),
+       /* set parameters to module waves */
+       SND_SOC_BYTES_EXT("Waves Set Param", WAVES_PARAM_COUNT,
+               hsw_waves_param_get, hsw_waves_param_put),
+};
+
+/* Create DMA buffer page table for DSP */
+static int create_adsp_page_table(struct snd_pcm_substream *substream,
+       struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd,
+       unsigned char *dma_area, size_t size, int pcm)
+{
+       struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
+       int i, pages, stream = substream->stream;
+
+       pages = snd_sgbuf_aligned_pages(size);
+
+       dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
+               dma_area, size, pages);
+
+       for (i = 0; i < pages; i++) {
+               u32 idx = (((i << 2) + i)) >> 1;
+               u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
+               u32 *pg_table;
+
+               dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
+
+               pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx);
+
+               if (i & 1)
+                       *pg_table |= (pfn << 4);
+               else
+                       *pg_table |= pfn;
+       }
+
+       return 0;
+}
+
+/* this may get called several times by oss emulation */
+static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw *hsw = pdata->hsw;
+       struct sst_module *module_data;
+       struct sst_dsp *dsp;
+       struct snd_dma_buffer *dmab;
+       enum sst_hsw_stream_type stream_type;
+       enum sst_hsw_stream_path_id path_id;
+       u32 rate, bits, map, pages, module_id;
+       u8 channels;
+       int ret, dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
+
+       /* check if we are being called a subsequent time */
+       if (pcm_data->allocated) {
+               ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
+               if (ret < 0)
+                       dev_dbg(rtd->dev, "error: reset stream failed %d\n",
+                               ret);
+
+               ret = sst_hsw_stream_free(hsw, pcm_data->stream);
+               if (ret < 0) {
+                       dev_dbg(rtd->dev, "error: free stream failed %d\n",
+                               ret);
+                       return ret;
+               }
+               pcm_data->allocated = false;
+
+               pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
+                       hsw_notify_pointer, pcm_data);
+               if (pcm_data->stream == NULL) {
+                       dev_err(rtd->dev, "error: failed to create stream\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* stream direction */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
+       else
+               path_id = SST_HSW_STREAM_PATH_SSP0_IN;
+
+       /* DSP stream type depends on DAI ID */
+       switch (rtd->cpu_dai->id) {
+       case 0:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
+                       module_id = SST_HSW_MODULE_PCM_SYSTEM;
+               }
+               else {
+                       stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
+                       module_id = SST_HSW_MODULE_PCM_CAPTURE;
+               }
+               break;
+       case 1:
+       case 2:
+               stream_type = SST_HSW_STREAM_TYPE_RENDER;
+               module_id = SST_HSW_MODULE_PCM;
+               break;
+       case 3:
+               /* path ID needs to be OUT for loopback */
+               stream_type = SST_HSW_STREAM_TYPE_LOOPBACK;
+               path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
+               module_id = SST_HSW_MODULE_PCM_REFERENCE;
+               break;
+       default:
+               dev_err(rtd->dev, "error: invalid DAI ID %d\n",
+                       rtd->cpu_dai->id);
+               return -EINVAL;
+       };
+
+       ret = sst_hsw_stream_format(hsw, pcm_data->stream,
+               path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: failed to set format %d\n", ret);
+               return ret;
+       }
+
+       rate = params_rate(params);
+       ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: could not set rate %d\n", rate);
+               return ret;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bits = SST_HSW_DEPTH_16BIT;
+               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               bits = SST_HSW_DEPTH_32BIT;
+               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 24);
+               break;
+       case SNDRV_PCM_FORMAT_S8:
+               bits = SST_HSW_DEPTH_8BIT;
+               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 8);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               bits = SST_HSW_DEPTH_32BIT;
+               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32);
+               break;
+       default:
+               dev_err(rtd->dev, "error: invalid format %d\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: could not set bits %d\n", bits);
+               return ret;
+       }
+
+       channels = params_channels(params);
+       map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO);
+       sst_hsw_stream_set_map_config(hsw, pcm_data->stream,
+                       map, SST_HSW_CHANNEL_CONFIG_STEREO);
+
+       ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: could not set channels %d\n",
+                       channels);
+               return ret;
+       }
+
+       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n",
+                       params_buffer_bytes(params), ret);
+               return ret;
+       }
+
+       dmab = snd_pcm_get_dma_buf(substream);
+
+       ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area,
+               runtime->dma_bytes, rtd->cpu_dai->id);
+       if (ret < 0)
+               return ret;
+
+       sst_hsw_stream_set_style(hsw, pcm_data->stream,
+               SST_HSW_INTERLEAVING_PER_CHANNEL);
+
+       if (runtime->dma_bytes % PAGE_SIZE)
+               pages = (runtime->dma_bytes / PAGE_SIZE) + 1;
+       else
+               pages = runtime->dma_bytes / PAGE_SIZE;
+
+       ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
+               pdata->dmab[rtd->cpu_dai->id][substream->stream].addr,
+               pages, runtime->dma_bytes, 0,
+               snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
+               return ret;
+       }
+
+       dsp = sst_hsw_get_dsp(hsw);
+
+       module_data = sst_module_get_from_id(dsp, module_id);
+       if (module_data == NULL) {
+               dev_err(rtd->dev, "error: failed to get module config\n");
+               return -EINVAL;
+       }
+
+       sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
+               pcm_data->runtime);
+
+       ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
+               return ret;
+       }
+
+       if (!pcm_data->allocated) {
+               /* Set previous saved volume */
+               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
+                               0, pcm_data->volume[0]);
+               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
+                               1, pcm_data->volume[1]);
+               pcm_data->allocated = true;
+       }
+
+       ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
+       if (ret < 0)
+               dev_err(rtd->dev, "error: failed to pause %d\n", ret);
+
+       return 0;
+}
+
+static int hsw_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw_stream *sst_stream;
+       struct sst_hsw *hsw = pdata->hsw;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       snd_pcm_uframes_t pos;
+       int dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
+       sst_stream = pcm_data->stream;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               sst_hsw_stream_set_silence_start(hsw, sst_stream, false);
+               sst_hsw_stream_resume(hsw, pcm_data->stream, 0);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               sst_hsw_stream_set_silence_start(hsw, sst_stream, false);
+               sst_hsw_stream_pause(hsw, pcm_data->stream, 0);
+               break;
+       case SNDRV_PCM_TRIGGER_DRAIN:
+               pos = runtime->control->appl_ptr % runtime->buffer_size;
+               sst_hsw_stream_set_old_position(hsw, pcm_data->stream, pos);
+               sst_hsw_stream_set_silence_start(hsw, sst_stream, true);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
+{
+       struct hsw_pcm_data *pcm_data = data;
+       struct snd_pcm_substream *substream = pcm_data->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_hsw *hsw = pdata->hsw;
+       u32 pos;
+       snd_pcm_uframes_t position = bytes_to_frames(runtime,
+                sst_hsw_get_dsp_position(hsw, pcm_data->stream));
+       unsigned char *dma_area = runtime->dma_area;
+       snd_pcm_uframes_t dma_frames =
+               bytes_to_frames(runtime, runtime->dma_bytes);
+       snd_pcm_uframes_t old_position;
+       ssize_t samples;
+
+       pos = frames_to_bytes(runtime,
+               (runtime->control->appl_ptr % runtime->buffer_size));
+
+       dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+
+       /* SST fw don't know where to stop dma
+        * So, SST driver need to clean the data which has been consumed
+        */
+       if (dma_area == NULL || dma_frames <= 0
+               || (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               || !sst_hsw_stream_get_silence_start(hsw, stream)) {
+               snd_pcm_period_elapsed(substream);
+               return pos;
+       }
+
+       old_position = sst_hsw_stream_get_old_position(hsw, stream);
+       if (position > old_position) {
+               if (position < dma_frames) {
+                       samples = SST_SAMPLES(runtime, position - old_position);
+                       snd_pcm_format_set_silence(runtime->format,
+                               SST_OLD_POSITION(dma_area,
+                                       runtime, old_position),
+                               samples);
+               } else
+                       dev_err(rtd->dev, "PCM: position is wrong\n");
+       } else {
+               if (old_position < dma_frames) {
+                       samples = SST_SAMPLES(runtime,
+                               dma_frames - old_position);
+                       snd_pcm_format_set_silence(runtime->format,
+                               SST_OLD_POSITION(dma_area,
+                                       runtime, old_position),
+                               samples);
+               } else
+                       dev_err(rtd->dev, "PCM: dma_bytes is wrong\n");
+               if (position < dma_frames) {
+                       samples = SST_SAMPLES(runtime, position);
+                       snd_pcm_format_set_silence(runtime->format,
+                               dma_area, samples);
+               } else
+                       dev_err(rtd->dev, "PCM: position is wrong\n");
+       }
+       sst_hsw_stream_set_old_position(hsw, stream, position);
+
+       /* let alsa know we have play a period */
+       snd_pcm_period_elapsed(substream);
+       return pos;
+}
+
+static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw *hsw = pdata->hsw;
+       snd_pcm_uframes_t offset;
+       uint64_t ppos;
+       u32 position;
+       int dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
+       position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
+
+       offset = bytes_to_frames(runtime, position);
+       ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
+
+       dev_vdbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
+               position, ppos);
+       return offset;
+}
+
+static int hsw_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw *hsw = pdata->hsw;
+       int dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
+
+       mutex_lock(&pcm_data->mutex);
+       pm_runtime_get_sync(pdata->dev);
+
+       snd_soc_pcm_set_drvdata(rtd, pcm_data);
+       pcm_data->substream = substream;
+
+       snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware);
+
+       pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
+               hsw_notify_pointer, pcm_data);
+       if (pcm_data->stream == NULL) {
+               dev_err(rtd->dev, "error: failed to create stream\n");
+               pm_runtime_mark_last_busy(pdata->dev);
+               pm_runtime_put_autosuspend(pdata->dev);
+               mutex_unlock(&pcm_data->mutex);
+               return -EINVAL;
+       }
+
+       mutex_unlock(&pcm_data->mutex);
+       return 0;
+}
+
+static int hsw_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw *hsw = pdata->hsw;
+       int ret, dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
+
+       mutex_lock(&pcm_data->mutex);
+       ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
+       if (ret < 0) {
+               dev_dbg(rtd->dev, "error: reset stream failed %d\n", ret);
+               goto out;
+       }
+
+       ret = sst_hsw_stream_free(hsw, pcm_data->stream);
+       if (ret < 0) {
+               dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
+               goto out;
+       }
+       pcm_data->allocated = 0;
+       pcm_data->stream = NULL;
+
+out:
+       pm_runtime_mark_last_busy(pdata->dev);
+       pm_runtime_put_autosuspend(pdata->dev);
+       mutex_unlock(&pcm_data->mutex);
+       return ret;
+}
+
+static struct snd_pcm_ops hsw_pcm_ops = {
+       .open           = hsw_pcm_open,
+       .close          = hsw_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = hsw_pcm_hw_params,
+       .hw_free        = hsw_pcm_hw_free,
+       .trigger        = hsw_pcm_trigger,
+       .pointer        = hsw_pcm_pointer,
+       .page           = snd_pcm_sgbuf_ops_page,
+};
+
+static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
+{
+       struct sst_hsw *hsw = pdata->hsw;
+       struct hsw_pcm_data *pcm_data;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+
+               /* create new runtime module, use same offset if recreated */
+               pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
+                       mod_map[i].mod_id, pcm_data->persistent_offset);
+               if (pcm_data->runtime == NULL)
+                       goto err;
+               pcm_data->persistent_offset =
+                       pcm_data->runtime->persistent_offset;
+       }
+
+       /* create runtime blocks for module waves */
+       if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) {
+               pdata->runtime_waves = sst_hsw_runtime_module_create(hsw,
+                       SST_HSW_MODULE_WAVES, 0);
+               if (pdata->runtime_waves == NULL)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       for (--i; i >= 0; i--) {
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+               sst_hsw_runtime_module_free(pcm_data->runtime);
+       }
+
+       return -ENODEV;
+}
+
+static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
+{
+       struct sst_hsw *hsw = pdata->hsw;
+       struct hsw_pcm_data *pcm_data;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+               sst_hsw_runtime_module_free(pcm_data->runtime);
+       }
+       if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) {
+               sst_hsw_runtime_module_free(pdata->runtime_waves);
+       }
+}
+
+static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+       struct hsw_priv_data *priv_data = dev_get_drvdata(platform->dev);
+       struct device *dev = pdata->dma_dev;
+       int ret = 0;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+                       pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+                       SNDRV_DMA_TYPE_DEV_SG,
+                       dev,
+                       hsw_pcm_hardware.buffer_bytes_max,
+                       hsw_pcm_hardware.buffer_bytes_max);
+               if (ret) {
+                       dev_err(rtd->dev, "dma buffer allocation failed %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+               priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm;
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
+               priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm;
+
+       return ret;
+}
+
+#define HSW_FORMATS \
+       (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_driver hsw_dais[] = {
+       {
+               .name  = "System Pin",
+               .id = HSW_PCM_DAI_ID_SYSTEM,
+               .playback = {
+                       .stream_name = "System Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
+               },
+               .capture = {
+                       .stream_name = "Analog Capture",
+                       .channels_min = 2,
+                       .channels_max = 4,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
+               },
+       },
+       {
+               /* PCM */
+               .name  = "Offload0 Pin",
+               .id = HSW_PCM_DAI_ID_OFFLOAD0,
+               .playback = {
+                       .stream_name = "Offload0 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = HSW_FORMATS,
+               },
+       },
+       {
+               /* PCM */
+               .name  = "Offload1 Pin",
+               .id = HSW_PCM_DAI_ID_OFFLOAD1,
+               .playback = {
+                       .stream_name = "Offload1 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = HSW_FORMATS,
+               },
+       },
+       {
+               .name  = "Loopback Pin",
+               .id = HSW_PCM_DAI_ID_LOOPBACK,
+               .capture = {
+                       .stream_name = "Loopback Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
+               },
+       },
+};
+
+static const struct snd_soc_dapm_widget widgets[] = {
+
+       /* Backend DAIs  */
+       SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+       /* Global Playback Mixer */
+       SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route graph[] = {
+
+       /* Playback Mixer */
+       {"Playback VMixer", NULL, "System Playback"},
+       {"Playback VMixer", NULL, "Offload0 Playback"},
+       {"Playback VMixer", NULL, "Offload1 Playback"},
+
+       {"SSP0 CODEC OUT", NULL, "Playback VMixer"},
+
+       {"Analog Capture", NULL, "SSP0 CODEC IN"},
+};
+
+static int hsw_pcm_probe(struct snd_soc_platform *platform)
+{
+       struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform);
+       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+       struct device *dma_dev, *dev;
+       int i, ret = 0;
+
+       if (!pdata)
+               return -ENODEV;
+
+       dev = platform->dev;
+       dma_dev = pdata->dma_dev;
+
+       priv_data->hsw = pdata->dsp;
+       priv_data->dev = platform->dev;
+       priv_data->pm_state = HSW_PM_STATE_D0;
+       priv_data->soc_card = platform->component.card;
+
+       /* allocate DSP buffer page tables */
+       for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
+
+               /* playback */
+               if (hsw_dais[i].playback.channels_min) {
+                       mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_PLAYBACK].mutex);
+                       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
+                               PAGE_SIZE, &priv_data->dmab[i][0]);
+                       if (ret < 0)
+                               goto err;
+               }
+
+               /* capture */
+               if (hsw_dais[i].capture.channels_min) {
+                       mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_CAPTURE].mutex);
+                       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
+                               PAGE_SIZE, &priv_data->dmab[i][1]);
+                       if (ret < 0)
+                               goto err;
+               }
+       }
+
+       /* allocate runtime modules */
+       ret = hsw_pcm_create_modules(priv_data);
+       if (ret < 0)
+               goto err;
+
+       /* enable runtime PM with auto suspend */
+       pm_runtime_set_autosuspend_delay(platform->dev,
+               SST_RUNTIME_SUSPEND_DELAY);
+       pm_runtime_use_autosuspend(platform->dev);
+       pm_runtime_enable(platform->dev);
+       pm_runtime_idle(platform->dev);
+
+       return 0;
+
+err:
+       for (--i; i >= 0; i--) {
+               if (hsw_dais[i].playback.channels_min)
+                       snd_dma_free_pages(&priv_data->dmab[i][0]);
+               if (hsw_dais[i].capture.channels_min)
+                       snd_dma_free_pages(&priv_data->dmab[i][1]);
+       }
+       return ret;
+}
+
+static int hsw_pcm_remove(struct snd_soc_platform *platform)
+{
+       struct hsw_priv_data *priv_data =
+               snd_soc_platform_get_drvdata(platform);
+       int i;
+
+       pm_runtime_disable(platform->dev);
+       hsw_pcm_free_modules(priv_data);
+
+       for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
+               if (hsw_dais[i].playback.channels_min)
+                       snd_dma_free_pages(&priv_data->dmab[i][0]);
+               if (hsw_dais[i].capture.channels_min)
+                       snd_dma_free_pages(&priv_data->dmab[i][1]);
+       }
+
+       return 0;
+}
+
+static struct snd_soc_platform_driver hsw_soc_platform = {
+       .probe          = hsw_pcm_probe,
+       .remove         = hsw_pcm_remove,
+       .ops            = &hsw_pcm_ops,
+       .pcm_new        = hsw_pcm_new,
+};
+
+static const struct snd_soc_component_driver hsw_dai_component = {
+       .name = "haswell-dai",
+       .controls = hsw_volume_controls,
+       .num_controls = ARRAY_SIZE(hsw_volume_controls),
+       .dapm_widgets = widgets,
+       .num_dapm_widgets = ARRAY_SIZE(widgets),
+       .dapm_routes = graph,
+       .num_dapm_routes = ARRAY_SIZE(graph),
+};
+
+static int hsw_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+       struct hsw_priv_data *priv_data;
+       int ret;
+
+       if (!sst_pdata)
+               return -EINVAL;
+
+       priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL);
+       if (!priv_data)
+               return -ENOMEM;
+
+       ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
+       if (ret < 0)
+               return -ENODEV;
+
+       priv_data->hsw = sst_pdata->dsp;
+       platform_set_drvdata(pdev, priv_data);
+
+       ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
+       if (ret < 0)
+               goto err_plat;
+
+       ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component,
+               hsw_dais, ARRAY_SIZE(hsw_dais));
+       if (ret < 0)
+               goto err_comp;
+
+       return 0;
+
+err_comp:
+       snd_soc_unregister_platform(&pdev->dev);
+err_plat:
+       sst_hsw_dsp_free(&pdev->dev, sst_pdata);
+       return 0;
+}
+
+static int hsw_pcm_dev_remove(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+
+       snd_soc_unregister_platform(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
+       sst_hsw_dsp_free(&pdev->dev, sst_pdata);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int hsw_pcm_runtime_idle(struct device *dev)
+{
+       return 0;
+}
+
+static int hsw_pcm_runtime_suspend(struct device *dev)
+{
+       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+       struct sst_hsw *hsw = pdata->hsw;
+       int ret;
+
+       if (pdata->pm_state >= HSW_PM_STATE_RTD3)
+               return 0;
+
+       /* fw modules will be unloaded on RTD3, set flag to track */
+       if (sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) {
+               ret = sst_hsw_module_disable(hsw, SST_HSW_MODULE_WAVES, 0);
+               if (ret < 0)
+                       return ret;
+               sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES);
+       }
+       sst_hsw_dsp_runtime_suspend(hsw);
+       sst_hsw_dsp_runtime_sleep(hsw);
+       pdata->pm_state = HSW_PM_STATE_RTD3;
+
+       return 0;
+}
+
+static int hsw_pcm_runtime_resume(struct device *dev)
+{
+       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+       struct sst_hsw *hsw = pdata->hsw;
+       int ret;
+
+       if (pdata->pm_state != HSW_PM_STATE_RTD3)
+               return 0;
+
+       ret = sst_hsw_dsp_load(hsw);
+       if (ret < 0) {
+               dev_err(dev, "failed to reload %d\n", ret);
+               return ret;
+       }
+
+       ret = hsw_pcm_create_modules(pdata);
+       if (ret < 0) {
+               dev_err(dev, "failed to create modules %d\n", ret);
+               return ret;
+       }
+
+       ret = sst_hsw_dsp_runtime_resume(hsw);
+       if (ret < 0)
+               return ret;
+       else if (ret == 1) /* no action required */
+               return 0;
+
+       /* check flag when resume */
+       if (sst_hsw_is_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES)) {
+               ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0);
+               if (ret < 0)
+                       return ret;
+               /* put parameters from buffer to dsp */
+               ret = sst_hsw_launch_param_buf(hsw);
+               if (ret < 0)
+                       return ret;
+               /* unset flag */
+               sst_hsw_set_module_disabled_rtd3(hsw, SST_HSW_MODULE_WAVES);
+       }
+
+       pdata->pm_state = HSW_PM_STATE_D0;
+       return ret;
+}
+
+#else
+#define hsw_pcm_runtime_idle           NULL
+#define hsw_pcm_runtime_suspend                NULL
+#define hsw_pcm_runtime_resume         NULL
+#endif
+
+#ifdef CONFIG_PM
+
+static void hsw_pcm_complete(struct device *dev)
+{
+       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+       struct sst_hsw *hsw = pdata->hsw;
+       struct hsw_pcm_data *pcm_data;
+       int i, err;
+
+       if (pdata->pm_state != HSW_PM_STATE_D3)
+               return;
+
+       err = sst_hsw_dsp_load(hsw);
+       if (err < 0) {
+               dev_err(dev, "failed to reload %d\n", err);
+               return;
+       }
+
+       err = hsw_pcm_create_modules(pdata);
+       if (err < 0) {
+               dev_err(dev, "failed to create modules %d\n", err);
+               return;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+
+               if (!pcm_data->substream)
+                       continue;
+
+               err = sst_module_runtime_restore(pcm_data->runtime,
+                       &pcm_data->context);
+               if (err < 0)
+                       dev_err(dev, "failed to restore context for PCM %d\n", i);
+       }
+
+       snd_soc_resume(pdata->soc_card->dev);
+
+       err = sst_hsw_dsp_runtime_resume(hsw);
+       if (err < 0)
+               return;
+       else if (err == 1) /* no action required */
+               return;
+
+       pdata->pm_state = HSW_PM_STATE_D0;
+       return;
+}
+
+static int hsw_pcm_prepare(struct device *dev)
+{
+       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+       struct sst_hsw *hsw = pdata->hsw;
+       struct hsw_pcm_data *pcm_data;
+       int i, err;
+
+       if (pdata->pm_state == HSW_PM_STATE_D3)
+               return 0;
+       else if (pdata->pm_state == HSW_PM_STATE_D0) {
+               /* suspend all active streams */
+               for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+                       pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+
+                       if (!pcm_data->substream)
+                               continue;
+                       dev_dbg(dev, "suspending pcm %d\n", i);
+                       snd_pcm_suspend_all(pcm_data->hsw_pcm);
+
+                       /* We need to wait until the DSP FW stops the streams */
+                       msleep(2);
+               }
+
+               /* preserve persistent memory */
+               for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+                       pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+
+                       if (!pcm_data->substream)
+                               continue;
+
+                       dev_dbg(dev, "saving context pcm %d\n", i);
+                       err = sst_module_runtime_save(pcm_data->runtime,
+                               &pcm_data->context);
+                       if (err < 0)
+                               dev_err(dev, "failed to save context for PCM %d\n", i);
+               }
+               /* enter D3 state and stall */
+               sst_hsw_dsp_runtime_suspend(hsw);
+               /* put the DSP to sleep */
+               sst_hsw_dsp_runtime_sleep(hsw);
+       }
+
+       snd_soc_suspend(pdata->soc_card->dev);
+       snd_soc_poweroff(pdata->soc_card->dev);
+
+       pdata->pm_state = HSW_PM_STATE_D3;
+
+       return 0;
+}
+
+#else
+#define hsw_pcm_prepare                NULL
+#define hsw_pcm_complete       NULL
+#endif
+
+static const struct dev_pm_ops hsw_pcm_pm = {
+       .runtime_idle = hsw_pcm_runtime_idle,
+       .runtime_suspend = hsw_pcm_runtime_suspend,
+       .runtime_resume = hsw_pcm_runtime_resume,
+       .prepare = hsw_pcm_prepare,
+       .complete = hsw_pcm_complete,
+};
+
+static struct platform_driver hsw_pcm_driver = {
+       .driver = {
+               .name = "haswell-pcm-audio",
+               .pm = &hsw_pcm_pm,
+       },
+
+       .probe = hsw_pcm_dev_probe,
+       .remove = hsw_pcm_dev_remove,
+};
+module_platform_driver(hsw_pcm_driver);
+
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Haswell/Lynxpoint + Broadwell/Wildcatpoint PCM");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:haswell-pcm-audio");
diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c
deleted file mode 100644 (file)
index 90b7a57..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform
- *
- *  Copyright (C) 2010 Intel Corp
- *  Author: Vinod Koul <vinod.koul@intel.com>
- *  Author: Harsha Priya <priya.harsha@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include "../codecs/sn95031.h"
-
-#define MID_MONO 1
-#define MID_STEREO 2
-#define MID_MAX_CAP 5
-#define MFLD_JACK_INSERT 0x04
-
-enum soc_mic_bias_zones {
-       MFLD_MV_START = 0,
-       /* mic bias volutage range for Headphones*/
-       MFLD_MV_HP = 400,
-       /* mic bias volutage range for American Headset*/
-       MFLD_MV_AM_HS = 650,
-       /* mic bias volutage range for Headset*/
-       MFLD_MV_HS = 2000,
-       MFLD_MV_UNDEFINED,
-};
-
-static unsigned int    hs_switch;
-static unsigned int    lo_dac;
-static struct snd_soc_codec *mfld_codec;
-
-struct mfld_mc_private {
-       void __iomem *int_base;
-       u8 interrupt_status;
-};
-
-struct snd_soc_jack mfld_jack;
-
-/*Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin mfld_jack_pins[] = {
-       {
-               .pin = "Headphones",
-               .mask = SND_JACK_HEADPHONE,
-       },
-       {
-               .pin = "AMIC1",
-               .mask = SND_JACK_MICROPHONE,
-       },
-};
-
-/* jack detection voltage zones */
-static struct snd_soc_jack_zone mfld_zones[] = {
-       {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
-       {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET},
-};
-
-/* sound card controls */
-static const char *headset_switch_text[] = {"Earpiece", "Headset"};
-
-static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"};
-
-static const struct soc_enum headset_enum =
-       SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
-
-static const struct soc_enum lo_enum =
-       SOC_ENUM_SINGLE_EXT(4, lo_text);
-
-static int headset_get_switch(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = hs_switch;
-       return 0;
-}
-
-static int headset_set_switch(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_context *dapm = &card->dapm;
-
-       if (ucontrol->value.integer.value[0] == hs_switch)
-               return 0;
-
-       snd_soc_dapm_mutex_lock(dapm);
-
-       if (ucontrol->value.integer.value[0]) {
-               pr_debug("hs_set HS path\n");
-               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
-       } else {
-               pr_debug("hs_set EP path\n");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
-               snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
-       }
-
-       snd_soc_dapm_sync_unlocked(dapm);
-
-       snd_soc_dapm_mutex_unlock(dapm);
-
-       hs_switch = ucontrol->value.integer.value[0];
-
-       return 0;
-}
-
-static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
-{
-       snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
-       snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
-       snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
-       snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
-       snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
-       snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
-       if (hs_switch) {
-               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
-       } else {
-               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
-               snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
-       }
-}
-
-static int lo_get_switch(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = lo_dac;
-       return 0;
-}
-
-static int lo_set_switch(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_context *dapm = &card->dapm;
-
-       if (ucontrol->value.integer.value[0] == lo_dac)
-               return 0;
-
-       snd_soc_dapm_mutex_lock(dapm);
-
-       /* we dont want to work with last state of lineout so just enable all
-        * pins and then disable pins not required
-        */
-       lo_enable_out_pins(dapm);
-
-       switch (ucontrol->value.integer.value[0]) {
-       case 0:
-               pr_debug("set vibra path\n");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
-               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
-               break;
-
-       case 1:
-               pr_debug("set hs  path\n");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
-               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
-               break;
-
-       case 2:
-               pr_debug("set spkr path\n");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
-               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
-               break;
-
-       case 3:
-               pr_debug("set null path\n");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
-               snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
-               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
-               break;
-       }
-
-       snd_soc_dapm_sync_unlocked(dapm);
-
-       snd_soc_dapm_mutex_unlock(dapm);
-
-       lo_dac = ucontrol->value.integer.value[0];
-       return 0;
-}
-
-static const struct snd_kcontrol_new mfld_snd_controls[] = {
-       SOC_ENUM_EXT("Playback Switch", headset_enum,
-                       headset_get_switch, headset_set_switch),
-       SOC_ENUM_EXT("Lineout Mux", lo_enum,
-                       lo_get_switch, lo_set_switch),
-};
-
-static const struct snd_soc_dapm_widget mfld_widgets[] = {
-       SND_SOC_DAPM_HP("Headphones", NULL),
-       SND_SOC_DAPM_MIC("Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route mfld_map[] = {
-       {"Headphones", NULL, "HPOUTR"},
-       {"Headphones", NULL, "HPOUTL"},
-       {"Mic", NULL, "AMIC1"},
-};
-
-static void mfld_jack_check(unsigned int intr_status)
-{
-       struct mfld_jack_data jack_data;
-
-       jack_data.mfld_jack = &mfld_jack;
-       jack_data.intr_id = intr_status;
-
-       sn95031_jack_detection(&jack_data);
-       /* TODO: add american headset detection post gpiolib support */
-}
-
-static int mfld_init(struct snd_soc_pcm_runtime *runtime)
-{
-       struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
-       int ret_val;
-
-       mfld_codec = runtime->codec;
-
-       /* default is earpiece pin, userspace sets it explcitly */
-       snd_soc_dapm_disable_pin(dapm, "Headphones");
-       /* default is lineout NC, userspace sets it explcitly */
-       snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
-       snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
-       lo_dac = 3;
-       hs_switch = 0;
-       /* we dont use linein in this so set to NC */
-       snd_soc_dapm_disable_pin(dapm, "LINEINL");
-       snd_soc_dapm_disable_pin(dapm, "LINEINR");
-
-       /* Headset and button jack detection */
-       ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                       SND_JACK_BTN_1, &mfld_jack);
-       if (ret_val) {
-               pr_err("jack creation failed\n");
-               return ret_val;
-       }
-
-       ret_val = snd_soc_jack_add_pins(&mfld_jack,
-                       ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins);
-       if (ret_val) {
-               pr_err("adding jack pins failed\n");
-               return ret_val;
-       }
-       ret_val = snd_soc_jack_add_zones(&mfld_jack,
-                       ARRAY_SIZE(mfld_zones), mfld_zones);
-       if (ret_val) {
-               pr_err("adding jack zones failed\n");
-               return ret_val;
-       }
-
-       /* we want to check if anything is inserted at boot,
-        * so send a fake event to codec and it will read adc
-        * to find if anything is there or not */
-       mfld_jack_check(MFLD_JACK_INSERT);
-       return ret_val;
-}
-
-static struct snd_soc_dai_link mfld_msic_dailink[] = {
-       {
-               .name = "Medfield Headset",
-               .stream_name = "Headset",
-               .cpu_dai_name = "Headset-cpu-dai",
-               .codec_dai_name = "SN95031 Headset",
-               .codec_name = "sn95031",
-               .platform_name = "sst-platform",
-               .init = mfld_init,
-       },
-       {
-               .name = "Medfield Speaker",
-               .stream_name = "Speaker",
-               .cpu_dai_name = "Speaker-cpu-dai",
-               .codec_dai_name = "SN95031 Speaker",
-               .codec_name = "sn95031",
-               .platform_name = "sst-platform",
-               .init = NULL,
-       },
-       {
-               .name = "Medfield Vibra",
-               .stream_name = "Vibra1",
-               .cpu_dai_name = "Vibra1-cpu-dai",
-               .codec_dai_name = "SN95031 Vibra1",
-               .codec_name = "sn95031",
-               .platform_name = "sst-platform",
-               .init = NULL,
-       },
-       {
-               .name = "Medfield Haptics",
-               .stream_name = "Vibra2",
-               .cpu_dai_name = "Vibra2-cpu-dai",
-               .codec_dai_name = "SN95031 Vibra2",
-               .codec_name = "sn95031",
-               .platform_name = "sst-platform",
-               .init = NULL,
-       },
-       {
-               .name = "Medfield Compress",
-               .stream_name = "Speaker",
-               .cpu_dai_name = "Compress-cpu-dai",
-               .codec_dai_name = "SN95031 Speaker",
-               .codec_name = "sn95031",
-               .platform_name = "sst-platform",
-               .init = NULL,
-       },
-};
-
-/* SoC card */
-static struct snd_soc_card snd_soc_card_mfld = {
-       .name = "medfield_audio",
-       .owner = THIS_MODULE,
-       .dai_link = mfld_msic_dailink,
-       .num_links = ARRAY_SIZE(mfld_msic_dailink),
-
-       .controls = mfld_snd_controls,
-       .num_controls = ARRAY_SIZE(mfld_snd_controls),
-       .dapm_widgets = mfld_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
-       .dapm_routes = mfld_map,
-       .num_dapm_routes = ARRAY_SIZE(mfld_map),
-};
-
-static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
-{
-       struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev;
-
-       memcpy_fromio(&mc_private->interrupt_status,
-                       ((void *)(mc_private->int_base)),
-                       sizeof(u8));
-       return IRQ_WAKE_THREAD;
-}
-
-static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
-{
-       struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
-
-       if (mfld_jack.codec == NULL)
-               return IRQ_HANDLED;
-       mfld_jack_check(mc_drv_ctx->interrupt_status);
-
-       return IRQ_HANDLED;
-}
-
-static int snd_mfld_mc_probe(struct platform_device *pdev)
-{
-       int ret_val = 0, irq;
-       struct mfld_mc_private *mc_drv_ctx;
-       struct resource *irq_mem;
-
-       pr_debug("snd_mfld_mc_probe called\n");
-
-       /* retrive the irq number */
-       irq = platform_get_irq(pdev, 0);
-
-       /* audio interrupt base of SRAM location where
-        * interrupts are stored by System FW */
-       mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
-       if (!mc_drv_ctx) {
-               pr_err("allocation failed\n");
-               return -ENOMEM;
-       }
-
-       irq_mem = platform_get_resource_byname(
-                               pdev, IORESOURCE_MEM, "IRQ_BASE");
-       if (!irq_mem) {
-               pr_err("no mem resource given\n");
-               return -ENODEV;
-       }
-       mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start,
-                                                   resource_size(irq_mem));
-       if (!mc_drv_ctx->int_base) {
-               pr_err("Mapping of cache failed\n");
-               return -ENOMEM;
-       }
-       /* register for interrupt */
-       ret_val = devm_request_threaded_irq(&pdev->dev, irq,
-                       snd_mfld_jack_intr_handler,
-                       snd_mfld_jack_detection,
-                       IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
-       if (ret_val) {
-               pr_err("cannot register IRQ\n");
-               return ret_val;
-       }
-       /* register the soc card */
-       snd_soc_card_mfld.dev = &pdev->dev;
-       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld);
-       if (ret_val) {
-               pr_debug("snd_soc_register_card failed %d\n", ret_val);
-               return ret_val;
-       }
-       platform_set_drvdata(pdev, mc_drv_ctx);
-       pr_debug("successfully exited probe\n");
-       return 0;
-}
-
-static struct platform_driver snd_mfld_mc_driver = {
-       .driver = {
-               .name = "msic_audio",
-       },
-       .probe = snd_mfld_mc_probe,
-};
-
-module_platform_driver(snd_mfld_mc_driver);
-
-MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
-MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
-MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:msic-audio");
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c
deleted file mode 100644 (file)
index b3d8456..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Intel SST loader on ACPI systems
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/acpi.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include "sst-dsp.h"
-
-#define SST_LPT_DSP_DMA_ADDR_OFFSET    0x0F0000
-#define SST_WPT_DSP_DMA_ADDR_OFFSET    0x0FE000
-#define SST_LPT_DSP_DMA_SIZE           (1024 - 1)
-
-/* Descriptor for SST ASoC machine driver */
-struct sst_acpi_mach {
-       /* ACPI ID for the matching machine driver. Audio codec for instance */
-       const u8 id[ACPI_ID_LEN];
-       /* machine driver name */
-       const char *drv_name;
-       /* firmware file name */
-       const char *fw_filename;
-};
-
-/* Descriptor for setting up SST platform data */
-struct sst_acpi_desc {
-       const char *drv_name;
-       struct sst_acpi_mach *machines;
-       /* Platform resource indexes. Must set to -1 if not used */
-       int resindex_lpe_base;
-       int resindex_pcicfg_base;
-       int resindex_fw_base;
-       int irqindex_host_ipc;
-       int resindex_dma_base;
-       /* Unique number identifying the SST core on platform */
-       int sst_id;
-       /* DMA only valid when resindex_dma_base != -1*/
-       int dma_engine;
-       int dma_size;
-};
-
-struct sst_acpi_priv {
-       struct platform_device *pdev_mach;
-       struct platform_device *pdev_pcm;
-       struct sst_pdata sst_pdata;
-       struct sst_acpi_desc *desc;
-       struct sst_acpi_mach *mach;
-};
-
-static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
-{
-       struct platform_device *pdev = context;
-       struct device *dev = &pdev->dev;
-       struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
-       struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
-       struct sst_acpi_desc *desc = sst_acpi->desc;
-       struct sst_acpi_mach *mach = sst_acpi->mach;
-
-       sst_pdata->fw = fw;
-       if (!fw) {
-               dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
-               return;
-       }
-
-       /* register PCM and DAI driver */
-       sst_acpi->pdev_pcm =
-               platform_device_register_data(dev, desc->drv_name, -1,
-                                             sst_pdata, sizeof(*sst_pdata));
-       if (IS_ERR(sst_acpi->pdev_pcm)) {
-               dev_err(dev, "Cannot register device %s. Error %d\n",
-                       desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
-       }
-
-       return;
-}
-
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
-                                      void *context, void **ret)
-{
-       *(bool *)context = true;
-       return AE_OK;
-}
-
-static struct sst_acpi_mach *sst_acpi_find_machine(
-       struct sst_acpi_mach *machines)
-{
-       struct sst_acpi_mach *mach;
-       bool found = false;
-
-       for (mach = machines; mach->id[0]; mach++)
-               if (ACPI_SUCCESS(acpi_get_devices(mach->id,
-                                                 sst_acpi_mach_match,
-                                                 &found, NULL)) && found)
-                       return mach;
-
-       return NULL;
-}
-
-static int sst_acpi_probe(struct platform_device *pdev)
-{
-       const struct acpi_device_id *id;
-       struct device *dev = &pdev->dev;
-       struct sst_acpi_priv *sst_acpi;
-       struct sst_pdata *sst_pdata;
-       struct sst_acpi_mach *mach;
-       struct sst_acpi_desc *desc;
-       struct resource *mmio;
-       int ret = 0;
-
-       sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
-       if (sst_acpi == NULL)
-               return -ENOMEM;
-
-       id = acpi_match_device(dev->driver->acpi_match_table, dev);
-       if (!id)
-               return -ENODEV;
-
-       desc = (struct sst_acpi_desc *)id->driver_data;
-       mach = sst_acpi_find_machine(desc->machines);
-       if (mach == NULL) {
-               dev_err(dev, "No matching ASoC machine driver found\n");
-               return -ENODEV;
-       }
-
-       sst_pdata = &sst_acpi->sst_pdata;
-       sst_pdata->id = desc->sst_id;
-       sst_pdata->dma_dev = dev;
-       sst_acpi->desc = desc;
-       sst_acpi->mach = mach;
-
-       if (desc->resindex_dma_base >= 0) {
-               sst_pdata->dma_engine = desc->dma_engine;
-               sst_pdata->dma_base = desc->resindex_dma_base;
-               sst_pdata->dma_size = desc->dma_size;
-       }
-
-       if (desc->irqindex_host_ipc >= 0)
-               sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
-
-       if (desc->resindex_lpe_base >= 0) {
-               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
-                                            desc->resindex_lpe_base);
-               if (mmio) {
-                       sst_pdata->lpe_base = mmio->start;
-                       sst_pdata->lpe_size = resource_size(mmio);
-               }
-       }
-
-       if (desc->resindex_pcicfg_base >= 0) {
-               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
-                                            desc->resindex_pcicfg_base);
-               if (mmio) {
-                       sst_pdata->pcicfg_base = mmio->start;
-                       sst_pdata->pcicfg_size = resource_size(mmio);
-               }
-       }
-
-       if (desc->resindex_fw_base >= 0) {
-               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
-                                            desc->resindex_fw_base);
-               if (mmio) {
-                       sst_pdata->fw_base = mmio->start;
-                       sst_pdata->fw_size = resource_size(mmio);
-               }
-       }
-
-       platform_set_drvdata(pdev, sst_acpi);
-
-       /* register machine driver */
-       sst_acpi->pdev_mach =
-               platform_device_register_data(dev, mach->drv_name, -1,
-                                             sst_pdata, sizeof(*sst_pdata));
-       if (IS_ERR(sst_acpi->pdev_mach))
-               return PTR_ERR(sst_acpi->pdev_mach);
-
-       /* continue SST probing after firmware is loaded */
-       ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
-                                     dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
-       if (ret)
-               platform_device_unregister(sst_acpi->pdev_mach);
-
-       return ret;
-}
-
-static int sst_acpi_remove(struct platform_device *pdev)
-{
-       struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
-       struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
-
-       platform_device_unregister(sst_acpi->pdev_mach);
-       if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
-               platform_device_unregister(sst_acpi->pdev_pcm);
-       release_firmware(sst_pdata->fw);
-
-       return 0;
-}
-
-static struct sst_acpi_mach haswell_machines[] = {
-       { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
-       {}
-};
-
-static struct sst_acpi_desc sst_acpi_haswell_desc = {
-       .drv_name = "haswell-pcm-audio",
-       .machines = haswell_machines,
-       .resindex_lpe_base = 0,
-       .resindex_pcicfg_base = 1,
-       .resindex_fw_base = -1,
-       .irqindex_host_ipc = 0,
-       .sst_id = SST_DEV_ID_LYNX_POINT,
-       .dma_engine = SST_DMA_TYPE_DW,
-       .resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
-       .dma_size = SST_LPT_DSP_DMA_SIZE,
-};
-
-static struct sst_acpi_mach broadwell_machines[] = {
-       { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
-       {}
-};
-
-static struct sst_acpi_desc sst_acpi_broadwell_desc = {
-       .drv_name = "haswell-pcm-audio",
-       .machines = broadwell_machines,
-       .resindex_lpe_base = 0,
-       .resindex_pcicfg_base = 1,
-       .resindex_fw_base = -1,
-       .irqindex_host_ipc = 0,
-       .sst_id = SST_DEV_ID_WILDCAT_POINT,
-       .dma_engine = SST_DMA_TYPE_DW,
-       .resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
-       .dma_size = SST_LPT_DSP_DMA_SIZE,
-};
-
-static struct sst_acpi_mach baytrail_machines[] = {
-       { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
-       { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
-       {}
-};
-
-static struct sst_acpi_desc sst_acpi_baytrail_desc = {
-       .drv_name = "baytrail-pcm-audio",
-       .machines = baytrail_machines,
-       .resindex_lpe_base = 0,
-       .resindex_pcicfg_base = 1,
-       .resindex_fw_base = 2,
-       .irqindex_host_ipc = 5,
-       .sst_id = SST_DEV_ID_BYT,
-       .resindex_dma_base = -1,
-};
-
-static struct acpi_device_id sst_acpi_match[] = {
-       { "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
-       { "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
-       { "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
-       { }
-};
-MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
-
-static struct platform_driver sst_acpi_driver = {
-       .probe = sst_acpi_probe,
-       .remove = sst_acpi_remove,
-       .driver = {
-               .name = "sst-acpi",
-               .acpi_match_table = ACPI_PTR(sst_acpi_match),
-       },
-};
-module_platform_driver(sst_acpi_driver);
-
-MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
-MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c
deleted file mode 100644 (file)
index 90aa5c0..0000000
+++ /dev/null
@@ -1,1422 +0,0 @@
-/*
- *  sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
- *
- *  Copyright (C) 2013-14 Intel Corp
- *  Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
- *     Vinod Koul <vinod.koul@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  In the dpcm driver modelling when a particular FE/BE/Mixer/Pipe is active
- *  we forward the settings and parameters, rest we keep the values  in
- *  driver and forward when DAPM enables them
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/slab.h>
-#include <sound/soc.h>
-#include <sound/tlv.h>
-#include "sst-mfld-platform.h"
-#include "sst-atom-controls.h"
-
-static int sst_fill_byte_control(struct sst_data *drv,
-                                        u8 ipc_msg, u8 block,
-                                        u8 task_id, u8 pipe_id,
-                                        u16 len, void *cmd_data)
-{
-       struct snd_sst_bytes_v2 *byte_data = drv->byte_stream;
-
-       byte_data->type = SST_CMD_BYTES_SET;
-       byte_data->ipc_msg = ipc_msg;
-       byte_data->block = block;
-       byte_data->task_id = task_id;
-       byte_data->pipe_id = pipe_id;
-
-       if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) {
-               dev_err(&drv->pdev->dev, "command length too big (%u)", len);
-               return -EINVAL;
-       }
-       byte_data->len = len;
-       memcpy(byte_data->bytes, cmd_data, len);
-       print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET,
-                            byte_data, len + sizeof(*byte_data));
-       return 0;
-}
-
-static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
-                                u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
-                                void *cmd_data, u16 len)
-{
-       int ret = 0;
-
-       ret = sst_fill_byte_control(drv, ipc_msg,
-                               block, task_id, pipe_id, len, cmd_data);
-       if (ret < 0)
-               return ret;
-       return sst->ops->send_byte_stream(sst->dev, drv->byte_stream);
-}
-
-/**
- * sst_fill_and_send_cmd - generate the IPC message and send it to the FW
- * @ipc_msg:   type of IPC (CMD, SET_PARAMS, GET_PARAMS)
- * @cmd_data:  the IPC payload
- */
-static int sst_fill_and_send_cmd(struct sst_data *drv,
-                                u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
-                                void *cmd_data, u16 len)
-{
-       int ret;
-
-       mutex_lock(&drv->lock);
-       ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
-                                       task_id, pipe_id, cmd_data, len);
-       mutex_unlock(&drv->lock);
-
-       return ret;
-}
-
-/**
- * tx map value is a bitfield where each bit represents a FW channel
- *
- *                     3 2 1 0         # 0 = codec0, 1 = codec1
- *                     RLRLRLRL        # 3, 4 = reserved
- *
- * e.g. slot 0 rx map =        00001100b -> data from slot 0 goes into codec_in1 L,R
- */
-static u8 sst_ssp_tx_map[SST_MAX_TDM_SLOTS] = {
-       0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default rx map */
-};
-
-/**
- * rx map value is a bitfield where each bit represents a slot
- *
- *                       76543210      # 0 = slot 0, 1 = slot 1
- *
- * e.g. codec1_0 tx map = 00000101b -> data from codec_out1_0 goes into slot 0, 2
- */
-static u8 sst_ssp_rx_map[SST_MAX_TDM_SLOTS] = {
-       0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default tx map */
-};
-
-/**
- * NOTE: this is invoked with lock held
- */
-static int sst_send_slot_map(struct sst_data *drv)
-{
-       struct sst_param_sba_ssp_slot_map cmd;
-
-       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
-       cmd.header.command_id = SBA_SET_SSP_SLOT_MAP;
-       cmd.header.length = sizeof(struct sst_param_sba_ssp_slot_map)
-                               - sizeof(struct sst_dsp_header);
-
-       cmd.param_id = SBA_SET_SSP_SLOT_MAP;
-       cmd.param_len = sizeof(cmd.rx_slot_map) + sizeof(cmd.tx_slot_map)
-                                       + sizeof(cmd.ssp_index);
-       cmd.ssp_index = SSP_CODEC;
-
-       memcpy(cmd.rx_slot_map, &sst_ssp_tx_map[0], sizeof(cmd.rx_slot_map));
-       memcpy(cmd.tx_slot_map, &sst_ssp_rx_map[0], sizeof(cmd.tx_slot_map));
-
-       return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
-                       SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
-                             sizeof(cmd.header) + cmd.header.length);
-}
-
-int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
-                      struct snd_ctl_elem_info *uinfo)
-{
-       struct sst_enum *e = (struct sst_enum *)kcontrol->private_value;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = e->max;
-
-       if (uinfo->value.enumerated.item > e->max - 1)
-               uinfo->value.enumerated.item = e->max - 1;
-       strcpy(uinfo->value.enumerated.name,
-               e->texts[uinfo->value.enumerated.item]);
-
-       return 0;
-}
-
-/**
- * sst_slot_get - get the status of the interleaver/deinterleaver control
- *
- * Searches the map where the control status is stored, and gets the
- * channel/slot which is currently set for this enumerated control. Since it is
- * an enumerated control, there is only one possible value.
- */
-static int sst_slot_get(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct sst_enum *e = (void *)kcontrol->private_value;
-       struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
-       struct sst_data *drv = snd_soc_component_get_drvdata(c);
-       unsigned int ctl_no = e->reg;
-       unsigned int is_tx = e->tx;
-       unsigned int val, mux;
-       u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
-
-       mutex_lock(&drv->lock);
-       val = 1 << ctl_no;
-       /* search which slot/channel has this bit set - there should be only one */
-       for (mux = e->max; mux > 0;  mux--)
-               if (map[mux - 1] & val)
-                       break;
-
-       ucontrol->value.enumerated.item[0] = mux;
-       mutex_unlock(&drv->lock);
-
-       dev_dbg(c->dev, "%s - %s map = %#x\n",
-                       is_tx ? "tx channel" : "rx slot",
-                        e->texts[mux], mux ? map[mux - 1] : -1);
-       return 0;
-}
-
-/* sst_check_and_send_slot_map - helper for checking power state and sending
- * slot map cmd
- *
- * called with lock held
- */
-static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol *kcontrol)
-{
-       struct sst_enum *e = (void *)kcontrol->private_value;
-       int ret = 0;
-
-       if (e->w && e->w->power)
-               ret = sst_send_slot_map(drv);
-       else
-               dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n",
-                               kcontrol->id.name);
-       return ret;
-}
-
-/**
- * sst_slot_put - set the status of interleaver/deinterleaver control
- *
- * (de)interleaver controls are defined in opposite sense to be user-friendly
- *
- * Instead of the enum value being the value written to the register, it is the
- * register address; and the kcontrol number (register num) is the value written
- * to the register. This is so that there can be only one value for each
- * slot/channel since there is only one control for each slot/channel.
- *
- * This means that whenever an enum is set, we need to clear the bit
- * for that kcontrol_no for all the interleaver OR deinterleaver registers
- */
-static int sst_slot_put(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
-       struct sst_data *drv = snd_soc_component_get_drvdata(c);
-       struct sst_enum *e = (void *)kcontrol->private_value;
-       int i, ret = 0;
-       unsigned int ctl_no = e->reg;
-       unsigned int is_tx = e->tx;
-       unsigned int slot_channel_no;
-       unsigned int val, mux;
-       u8 *map;
-
-       map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
-
-       val = 1 << ctl_no;
-       mux = ucontrol->value.enumerated.item[0];
-       if (mux > e->max - 1)
-               return -EINVAL;
-
-       mutex_lock(&drv->lock);
-       /* first clear all registers of this bit */
-       for (i = 0; i < e->max; i++)
-               map[i] &= ~val;
-
-       if (mux == 0) {
-               /* kctl set to 'none' and we reset the bits so send IPC */
-               ret = sst_check_and_send_slot_map(drv, kcontrol);
-
-               mutex_unlock(&drv->lock);
-               return ret;
-       }
-
-       /* offset by one to take "None" into account */
-       slot_channel_no = mux - 1;
-       map[slot_channel_no] |= val;
-
-       dev_dbg(c->dev, "%s %s map = %#x\n",
-                       is_tx ? "tx channel" : "rx slot",
-                       e->texts[mux], map[slot_channel_no]);
-
-       ret = sst_check_and_send_slot_map(drv, kcontrol);
-
-       mutex_unlock(&drv->lock);
-       return ret;
-}
-
-static int sst_send_algo_cmd(struct sst_data *drv,
-                             struct sst_algo_control *bc)
-{
-       int len, ret = 0;
-       struct sst_cmd_set_params *cmd;
-
-       /*bc->max includes sizeof algos + length field*/
-       len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max;
-
-       cmd = kzalloc(len, GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-
-       SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id);
-       cmd->command_id = bc->cmd_id;
-       memcpy(cmd->params, bc->params, bc->max);
-
-       ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
-                               SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len);
-       kfree(cmd);
-       return ret;
-}
-
-/**
- * sst_find_and_send_pipe_algo - send all the algo parameters for a pipe
- *
- * The algos which are in each pipeline are sent to the firmware one by one
- *
- * Called with lock held
- */
-static int sst_find_and_send_pipe_algo(struct sst_data *drv,
-                                       const char *pipe, struct sst_ids *ids)
-{
-       int ret = 0;
-       struct sst_algo_control *bc;
-       struct sst_module *algo = NULL;
-
-       dev_dbg(&drv->pdev->dev, "Enter: widget=%s\n", pipe);
-
-       list_for_each_entry(algo, &ids->algo_list, node) {
-               bc = (void *)algo->kctl->private_value;
-
-               dev_dbg(&drv->pdev->dev, "Found algo control name=%s pipe=%s\n",
-                               algo->kctl->id.name, pipe);
-               ret = sst_send_algo_cmd(drv, bc);
-               if (ret)
-                       return ret;
-       }
-       return ret;
-}
-
-static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_info *uinfo)
-{
-       struct sst_algo_control *bc = (void *)kcontrol->private_value;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
-       uinfo->count = bc->max;
-
-       return 0;
-}
-
-static int sst_algo_control_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct sst_algo_control *bc = (void *)kcontrol->private_value;
-       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
-
-       switch (bc->type) {
-       case SST_ALGO_PARAMS:
-               memcpy(ucontrol->value.bytes.data, bc->params, bc->max);
-               break;
-       default:
-               dev_err(component->dev, "Invalid Input- algo type:%d\n",
-                               bc->type);
-               return -EINVAL;
-
-       }
-       return 0;
-}
-
-static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       int ret = 0;
-       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
-       struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
-       struct sst_algo_control *bc = (void *)kcontrol->private_value;
-
-       dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
-       mutex_lock(&drv->lock);
-       switch (bc->type) {
-       case SST_ALGO_PARAMS:
-               memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
-               break;
-       default:
-               mutex_unlock(&drv->lock);
-               dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
-                               bc->type);
-               return -EINVAL;
-       }
-       /*if pipe is enabled, need to send the algo params from here*/
-       if (bc->w && bc->w->power)
-               ret = sst_send_algo_cmd(drv, bc);
-       mutex_unlock(&drv->lock);
-
-       return ret;
-}
-
-static int sst_gain_ctl_info(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_info *uinfo)
-{
-       struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = mc->stereo ? 2 : 1;
-       uinfo->value.integer.min = mc->min;
-       uinfo->value.integer.max = mc->max;
-
-       return 0;
-}
-
-/**
- * sst_send_gain_cmd - send the gain algorithm IPC to the FW
- * @gv:                the stored value of gain (also contains rampduration)
- * @mute:      flag that indicates whether this was called from the
- *             digital_mute callback or directly. If called from the
- *             digital_mute callback, module will be muted/unmuted based on this
- *             flag. The flag is always 0 if called directly.
- *
- * Called with sst_data.lock held
- *
- * The user-set gain value is sent only if the user-controllable 'mute' control
- * is OFF (indicated by gv->mute). Otherwise, the mute value (MIN value) is
- * sent.
- */
-static int sst_send_gain_cmd(struct sst_data *drv, struct sst_gain_value *gv,
-                             u16 task_id, u16 loc_id, u16 module_id, int mute)
-{
-       struct sst_cmd_set_gain_dual cmd;
-
-       dev_dbg(&drv->pdev->dev, "Enter\n");
-
-       cmd.header.command_id = MMX_SET_GAIN;
-       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
-       cmd.gain_cell_num = 1;
-
-       if (mute || gv->mute) {
-               cmd.cell_gains[0].cell_gain_left = SST_GAIN_MIN_VALUE;
-               cmd.cell_gains[0].cell_gain_right = SST_GAIN_MIN_VALUE;
-       } else {
-               cmd.cell_gains[0].cell_gain_left = gv->l_gain;
-               cmd.cell_gains[0].cell_gain_right = gv->r_gain;
-       }
-
-       SST_FILL_DESTINATION(2, cmd.cell_gains[0].dest,
-                            loc_id, module_id);
-       cmd.cell_gains[0].gain_time_constant = gv->ramp_duration;
-
-       cmd.header.length = sizeof(struct sst_cmd_set_gain_dual)
-                               - sizeof(struct sst_dsp_header);
-
-       /* we are with lock held, so call the unlocked api  to send */
-       return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
-                               SST_FLAG_BLOCKED, task_id, 0, &cmd,
-                             sizeof(cmd.header) + cmd.header.length);
-}
-
-static int sst_gain_get(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
-       struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
-       struct sst_gain_value *gv = mc->gain_val;
-
-       switch (mc->type) {
-       case SST_GAIN_TLV:
-               ucontrol->value.integer.value[0] = gv->l_gain;
-               ucontrol->value.integer.value[1] = gv->r_gain;
-               break;
-
-       case SST_GAIN_MUTE:
-               ucontrol->value.integer.value[0] = gv->mute ? 1 : 0;
-               break;
-
-       case SST_GAIN_RAMP_DURATION:
-               ucontrol->value.integer.value[0] = gv->ramp_duration;
-               break;
-
-       default:
-               dev_err(component->dev, "Invalid Input- gain type:%d\n",
-                               mc->type);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int sst_gain_put(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       int ret = 0;
-       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
-       struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
-       struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
-       struct sst_gain_value *gv = mc->gain_val;
-
-       mutex_lock(&drv->lock);
-
-       switch (mc->type) {
-       case SST_GAIN_TLV:
-               gv->l_gain = ucontrol->value.integer.value[0];
-               gv->r_gain = ucontrol->value.integer.value[1];
-               dev_dbg(cmpnt->dev, "%s: Volume %d, %d\n",
-                               mc->pname, gv->l_gain, gv->r_gain);
-               break;
-
-       case SST_GAIN_MUTE:
-               gv->mute = !!ucontrol->value.integer.value[0];
-               dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute);
-               break;
-
-       case SST_GAIN_RAMP_DURATION:
-               gv->ramp_duration = ucontrol->value.integer.value[0];
-               dev_dbg(cmpnt->dev, "%s: Ramp Delay%d\n",
-                                       mc->pname, gv->ramp_duration);
-               break;
-
-       default:
-               mutex_unlock(&drv->lock);
-               dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n",
-                               mc->type);
-               return -EINVAL;
-       }
-
-       if (mc->w && mc->w->power)
-               ret = sst_send_gain_cmd(drv, gv, mc->task_id,
-                       mc->pipe_id | mc->instance_id, mc->module_id, 0);
-       mutex_unlock(&drv->lock);
-
-       return ret;
-}
-
-static int sst_set_pipe_gain(struct sst_ids *ids,
-                               struct sst_data *drv, int mute);
-
-static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol)
-{
-       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
-       struct sst_data *drv = snd_soc_component_get_drvdata(c);
-       struct sst_ids *ids = w->priv;
-
-       mutex_lock(&drv->lock);
-       sst_find_and_send_pipe_algo(drv, w->name, ids);
-       sst_set_pipe_gain(ids, drv, 0);
-       mutex_unlock(&drv->lock);
-
-       return 0;
-}
-
-static int sst_generic_modules_event(struct snd_soc_dapm_widget *w,
-                                    struct snd_kcontrol *k, int event)
-{
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               return sst_send_pipe_module_params(w, k);
-       return 0;
-}
-
-static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10, 10, 0);
-
-/* Look up table to convert MIXER SW bit regs to SWM inputs */
-static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = {
-       [SST_IP_CODEC0]         = SST_SWM_IN_CODEC0,
-       [SST_IP_CODEC1]         = SST_SWM_IN_CODEC1,
-       [SST_IP_LOOP0]          = SST_SWM_IN_SPROT_LOOP,
-       [SST_IP_LOOP1]          = SST_SWM_IN_MEDIA_LOOP1,
-       [SST_IP_LOOP2]          = SST_SWM_IN_MEDIA_LOOP2,
-       [SST_IP_PCM0]           = SST_SWM_IN_PCM0,
-       [SST_IP_PCM1]           = SST_SWM_IN_PCM1,
-       [SST_IP_MEDIA0]         = SST_SWM_IN_MEDIA0,
-       [SST_IP_MEDIA1]         = SST_SWM_IN_MEDIA1,
-       [SST_IP_MEDIA2]         = SST_SWM_IN_MEDIA2,
-       [SST_IP_MEDIA3]         = SST_SWM_IN_MEDIA3,
-};
-
-/**
- * fill_swm_input - fill in the SWM input ids given the register
- *
- * The register value is a bit-field inicated which mixer inputs are ON. Use the
- * lookup table to get the input-id and fill it in the structure.
- */
-static int fill_swm_input(struct snd_soc_component *cmpnt,
-               struct swm_input_ids *swm_input, unsigned int reg)
-{
-       uint i, is_set, nb_inputs = 0;
-       u16 input_loc_id;
-
-       dev_dbg(cmpnt->dev, "reg: %#x\n", reg);
-       for (i = 0; i < SST_SWM_INPUT_COUNT; i++) {
-               is_set = reg & BIT(i);
-               if (!is_set)
-                       continue;
-
-               input_loc_id = swm_mixer_input_ids[i];
-               SST_FILL_DESTINATION(2, swm_input->input_id,
-                                    input_loc_id, SST_DEFAULT_MODULE_ID);
-               nb_inputs++;
-               swm_input++;
-               dev_dbg(cmpnt->dev, "input id: %#x, nb_inputs: %d\n",
-                               input_loc_id, nb_inputs);
-
-               if (nb_inputs == SST_CMD_SWM_MAX_INPUTS) {
-                       dev_warn(cmpnt->dev, "SET_SWM cmd max inputs reached");
-                       break;
-               }
-       }
-       return nb_inputs;
-}
-
-
-/**
- * called with lock held
- */
-static int sst_set_pipe_gain(struct sst_ids *ids,
-                       struct sst_data *drv, int mute)
-{
-       int ret = 0;
-       struct sst_gain_mixer_control *mc;
-       struct sst_gain_value *gv;
-       struct sst_module *gain = NULL;
-
-       list_for_each_entry(gain, &ids->gain_list, node) {
-               struct snd_kcontrol *kctl = gain->kctl;
-
-               dev_dbg(&drv->pdev->dev, "control name=%s\n", kctl->id.name);
-               mc = (void *)kctl->private_value;
-               gv = mc->gain_val;
-
-               ret = sst_send_gain_cmd(drv, gv, mc->task_id,
-                       mc->pipe_id | mc->instance_id, mc->module_id, mute);
-               if (ret)
-                       return ret;
-       }
-       return ret;
-}
-
-static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w,
-                       struct snd_kcontrol *k, int event)
-{
-       struct sst_cmd_set_swm cmd;
-       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
-       struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
-       struct sst_ids *ids = w->priv;
-       bool set_mixer = false;
-       struct soc_mixer_control *mc;
-       int val = 0;
-       int i = 0;
-
-       dev_dbg(cmpnt->dev, "widget = %s\n", w->name);
-       /*
-        * Identify which mixer input is on and send the bitmap of the
-        * inputs as an IPC to the DSP.
-        */
-       for (i = 0; i < w->num_kcontrols; i++) {
-               if (dapm_kcontrol_get_value(w->kcontrols[i])) {
-                       mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
-                       val |= 1 << mc->shift;
-               }
-       }
-       dev_dbg(cmpnt->dev, "val = %#x\n", val);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-       case SND_SOC_DAPM_POST_PMD:
-               set_mixer = true;
-               break;
-       case SND_SOC_DAPM_POST_REG:
-               if (w->power)
-                       set_mixer = true;
-               break;
-       default:
-               set_mixer = false;
-       }
-
-       if (set_mixer == false)
-               return 0;
-
-       if (SND_SOC_DAPM_EVENT_ON(event) ||
-           event == SND_SOC_DAPM_POST_REG)
-               cmd.switch_state = SST_SWM_ON;
-       else
-               cmd.switch_state = SST_SWM_OFF;
-
-       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
-       /* MMX_SET_SWM == SBA_SET_SWM */
-       cmd.header.command_id = SBA_SET_SWM;
-
-       SST_FILL_DESTINATION(2, cmd.output_id,
-                            ids->location_id, SST_DEFAULT_MODULE_ID);
-       cmd.nb_inputs = fill_swm_input(cmpnt, &cmd.input[0], val);
-       cmd.header.length = offsetof(struct sst_cmd_set_swm, input)
-                               - sizeof(struct sst_dsp_header)
-                               + (cmd.nb_inputs * sizeof(cmd.input[0]));
-
-       return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
-                             ids->task_id, 0, &cmd,
-                             sizeof(cmd.header) + cmd.header.length);
-}
-
-/* SBA mixers - 16 inputs */
-#define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name)                                                        \
-       static const struct snd_kcontrol_new kctl_name[] = {                                    \
-               SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0),         \
-               SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0),         \
-               SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0),      \
-               SOC_DAPM_SINGLE("media_loop1_in Switch", SND_SOC_NOPM, SST_IP_LOOP1, 1, 0),     \
-               SOC_DAPM_SINGLE("media_loop2_in Switch", SND_SOC_NOPM, SST_IP_LOOP2, 1, 0),     \
-               SOC_DAPM_SINGLE("pcm0_in Switch", SND_SOC_NOPM, SST_IP_PCM0, 1, 0),             \
-               SOC_DAPM_SINGLE("pcm1_in Switch", SND_SOC_NOPM, SST_IP_PCM1, 1, 0),             \
-       }
-
-#define SST_SBA_MIXER_GRAPH_MAP(mix_name)                      \
-       { mix_name, "codec_in0 Switch", "codec_in0" },          \
-       { mix_name, "codec_in1 Switch", "codec_in1" },          \
-       { mix_name, "sprot_loop_in Switch",     "sprot_loop_in" },      \
-       { mix_name, "media_loop1_in Switch",    "media_loop1_in" },     \
-       { mix_name, "media_loop2_in Switch",    "media_loop2_in" },     \
-       { mix_name, "pcm0_in Switch",           "pcm0_in" },            \
-       { mix_name, "pcm1_in Switch",           "pcm1_in" }
-
-#define SST_MMX_DECLARE_MIX_CONTROLS(kctl_name)                                                \
-       static const struct snd_kcontrol_new kctl_name[] = {                            \
-               SOC_DAPM_SINGLE("media0_in Switch", SND_SOC_NOPM, SST_IP_MEDIA0, 1, 0), \
-               SOC_DAPM_SINGLE("media1_in Switch", SND_SOC_NOPM, SST_IP_MEDIA1, 1, 0), \
-               SOC_DAPM_SINGLE("media2_in Switch", SND_SOC_NOPM, SST_IP_MEDIA2, 1, 0), \
-               SOC_DAPM_SINGLE("media3_in Switch", SND_SOC_NOPM, SST_IP_MEDIA3, 1, 0), \
-       }
-
-SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media0_controls);
-SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media1_controls);
-
-/* 18 SBA mixers */
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm0_controls);
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm1_controls);
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls);
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls);
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls);
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls);
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls);
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls);
-SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls);
-
-/*
- * sst_handle_vb_timer - Start/Stop the DSP scheduler
- *
- * The DSP expects first cmd to be SBA_VB_START, so at first startup send
- * that.
- * DSP expects last cmd to be SBA_VB_IDLE, so at last shutdown send that.
- *
- * Do refcount internally so that we send command only at first start
- * and last end. Since SST driver does its own ref count, invoke sst's
- * power ops always!
- */
-int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
-{
-       int ret = 0;
-       struct sst_cmd_generic cmd;
-       struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
-       static int timer_usage;
-
-       if (enable)
-               cmd.header.command_id = SBA_VB_START;
-       else
-               cmd.header.command_id = SBA_IDLE;
-       dev_dbg(dai->dev, "enable=%u, usage=%d\n", enable, timer_usage);
-
-       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
-       cmd.header.length = 0;
-
-       if (enable) {
-               ret = sst->ops->power(sst->dev, true);
-               if (ret < 0)
-                       return ret;
-       }
-
-       mutex_lock(&drv->lock);
-       if (enable)
-               timer_usage++;
-       else
-               timer_usage--;
-
-       /*
-        * Send the command only if this call is the first enable or last
-        * disable
-        */
-       if ((enable && (timer_usage == 1)) ||
-           (!enable && (timer_usage == 0))) {
-               ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
-                               SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
-                               sizeof(cmd.header) + cmd.header.length);
-               if (ret && enable) {
-                       timer_usage--;
-                       enable  = false;
-               }
-       }
-       mutex_unlock(&drv->lock);
-
-       if (!enable)
-               sst->ops->power(sst->dev, false);
-       return ret;
-}
-
-/**
- * sst_ssp_config - contains SSP configuration for media UC
- */
-static const struct sst_ssp_config sst_ssp_configs = {
-       .ssp_id = SSP_CODEC,
-       .bits_per_slot = 24,
-       .slots = 4,
-       .ssp_mode = SSP_MODE_MASTER,
-       .pcm_mode = SSP_PCM_MODE_NETWORK,
-       .duplex = SSP_DUPLEX,
-       .ssp_protocol = SSP_MODE_PCM,
-       .fs_width = 1,
-       .fs_frequency = SSP_FS_48_KHZ,
-       .active_slot_map = 0xF,
-       .start_delay = 0,
-};
-
-int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable)
-{
-       struct sst_cmd_sba_hw_set_ssp cmd;
-       struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
-       const struct sst_ssp_config *config;
-
-       dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);
-
-       SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
-       cmd.header.command_id = SBA_HW_SET_SSP;
-       cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp)
-                               - sizeof(struct sst_dsp_header);
-
-       config = &sst_ssp_configs;
-       dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id);
-
-       if (enable)
-               cmd.switch_state = SST_SWITCH_ON;
-       else
-               cmd.switch_state = SST_SWITCH_OFF;
-
-       cmd.selection = config->ssp_id;
-       cmd.nb_bits_per_slots = config->bits_per_slot;
-       cmd.nb_slots = config->slots;
-       cmd.mode = config->ssp_mode | (config->pcm_mode << 1);
-       cmd.duplex = config->duplex;
-       cmd.active_tx_slot_map = config->active_slot_map;
-       cmd.active_rx_slot_map = config->active_slot_map;
-       cmd.frame_sync_frequency = config->fs_frequency;
-       cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH;
-       cmd.data_polarity = 1;
-       cmd.frame_sync_width = config->fs_width;
-       cmd.ssp_protocol = config->ssp_protocol;
-       cmd.start_delay = config->start_delay;
-       cmd.reserved1 = cmd.reserved2 = 0xFF;
-
-       return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
-                               SST_TASK_SBA, 0, &cmd,
-                               sizeof(cmd.header) + cmd.header.length);
-}
-
-static int sst_set_be_modules(struct snd_soc_dapm_widget *w,
-                        struct snd_kcontrol *k, int event)
-{
-       int ret = 0;
-       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
-       struct sst_data *drv = snd_soc_component_get_drvdata(c);
-
-       dev_dbg(c->dev, "Enter: widget=%s\n", w->name);
-
-       if (SND_SOC_DAPM_EVENT_ON(event)) {
-               ret = sst_send_slot_map(drv);
-               if (ret)
-                       return ret;
-               ret = sst_send_pipe_module_params(w, k);
-       }
-       return ret;
-}
-
-static int sst_set_media_path(struct snd_soc_dapm_widget *w,
-                             struct snd_kcontrol *k, int event)
-{
-       int ret = 0;
-       struct sst_cmd_set_media_path cmd;
-       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
-       struct sst_data *drv = snd_soc_component_get_drvdata(c);
-       struct sst_ids *ids = w->priv;
-
-       dev_dbg(c->dev, "widget=%s\n", w->name);
-       dev_dbg(c->dev, "task=%u, location=%#x\n",
-                               ids->task_id, ids->location_id);
-
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               cmd.switch_state = SST_PATH_ON;
-       else
-               cmd.switch_state = SST_PATH_OFF;
-
-       SST_FILL_DESTINATION(2, cmd.header.dst,
-                            ids->location_id, SST_DEFAULT_MODULE_ID);
-
-       /* MMX_SET_MEDIA_PATH == SBA_SET_MEDIA_PATH */
-       cmd.header.command_id = MMX_SET_MEDIA_PATH;
-       cmd.header.length = sizeof(struct sst_cmd_set_media_path)
-                               - sizeof(struct sst_dsp_header);
-
-       ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
-                             ids->task_id, 0, &cmd,
-                             sizeof(cmd.header) + cmd.header.length);
-       if (ret)
-               return ret;
-
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               ret = sst_send_pipe_module_params(w, k);
-       return ret;
-}
-
-static int sst_set_media_loop(struct snd_soc_dapm_widget *w,
-                       struct snd_kcontrol *k, int event)
-{
-       int ret = 0;
-       struct sst_cmd_sba_set_media_loop_map cmd;
-       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
-       struct sst_data *drv = snd_soc_component_get_drvdata(c);
-       struct sst_ids *ids = w->priv;
-
-       dev_dbg(c->dev, "Enter:widget=%s\n", w->name);
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               cmd.switch_state = SST_SWITCH_ON;
-       else
-               cmd.switch_state = SST_SWITCH_OFF;
-
-       SST_FILL_DESTINATION(2, cmd.header.dst,
-                            ids->location_id, SST_DEFAULT_MODULE_ID);
-
-       cmd.header.command_id = SBA_SET_MEDIA_LOOP_MAP;
-       cmd.header.length = sizeof(struct sst_cmd_sba_set_media_loop_map)
-                                - sizeof(struct sst_dsp_header);
-       cmd.param.part.cfg.rate = 2; /* 48khz */
-
-       cmd.param.part.cfg.format = ids->format; /* stereo/Mono */
-       cmd.param.part.cfg.s_length = 1; /* 24bit left justified */
-       cmd.map = 0; /* Algo sequence: Gain - DRP - FIR - IIR */
-
-       ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
-                             SST_TASK_SBA, 0, &cmd,
-                             sizeof(cmd.header) + cmd.header.length);
-       if (ret)
-               return ret;
-
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               ret = sst_send_pipe_module_params(w, k);
-       return ret;
-}
-
-static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
-       SST_AIF_IN("codec_in0", sst_set_be_modules),
-       SST_AIF_IN("codec_in1", sst_set_be_modules),
-       SST_AIF_OUT("codec_out0", sst_set_be_modules),
-       SST_AIF_OUT("codec_out1", sst_set_be_modules),
-
-       /* Media Paths */
-       /* MediaX IN paths are set via ALLOC, so no SET_MEDIA_PATH command */
-       SST_PATH_INPUT("media0_in", SST_TASK_MMX, SST_SWM_IN_MEDIA0, sst_generic_modules_event),
-       SST_PATH_INPUT("media1_in", SST_TASK_MMX, SST_SWM_IN_MEDIA1, NULL),
-       SST_PATH_INPUT("media2_in", SST_TASK_MMX, SST_SWM_IN_MEDIA2, sst_set_media_path),
-       SST_PATH_INPUT("media3_in", SST_TASK_MMX, SST_SWM_IN_MEDIA3, NULL),
-       SST_PATH_OUTPUT("media0_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA0, sst_set_media_path),
-       SST_PATH_OUTPUT("media1_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA1, sst_set_media_path),
-
-       /* SBA PCM Paths */
-       SST_PATH_INPUT("pcm0_in", SST_TASK_SBA, SST_SWM_IN_PCM0, sst_set_media_path),
-       SST_PATH_INPUT("pcm1_in", SST_TASK_SBA, SST_SWM_IN_PCM1, sst_set_media_path),
-       SST_PATH_OUTPUT("pcm0_out", SST_TASK_SBA, SST_SWM_OUT_PCM0, sst_set_media_path),
-       SST_PATH_OUTPUT("pcm1_out", SST_TASK_SBA, SST_SWM_OUT_PCM1, sst_set_media_path),
-       SST_PATH_OUTPUT("pcm2_out", SST_TASK_SBA, SST_SWM_OUT_PCM2, sst_set_media_path),
-
-       /* SBA Loops */
-       SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL),
-       SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL),
-       SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL),
-       SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop),
-       SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop),
-       SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop),
-
-       /* Media Mixers */
-       SST_SWM_MIXER("media0_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA0,
-                     sst_mix_media0_controls, sst_swm_mixer_event),
-       SST_SWM_MIXER("media1_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA1,
-                     sst_mix_media1_controls, sst_swm_mixer_event),
-
-       /* SBA PCM mixers */
-       SST_SWM_MIXER("pcm0_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM0,
-                     sst_mix_pcm0_controls, sst_swm_mixer_event),
-       SST_SWM_MIXER("pcm1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM1,
-                     sst_mix_pcm1_controls, sst_swm_mixer_event),
-       SST_SWM_MIXER("pcm2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM2,
-                     sst_mix_pcm2_controls, sst_swm_mixer_event),
-
-       /* SBA Loop mixers */
-       SST_SWM_MIXER("sprot_loop_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP,
-                     sst_mix_sprot_l0_controls, sst_swm_mixer_event),
-       SST_SWM_MIXER("media_loop1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1,
-                     sst_mix_media_l1_controls, sst_swm_mixer_event),
-       SST_SWM_MIXER("media_loop2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2,
-                     sst_mix_media_l2_controls, sst_swm_mixer_event),
-
-       /* SBA Backend mixers */
-       SST_SWM_MIXER("codec_out0 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC0,
-                     sst_mix_codec0_controls, sst_swm_mixer_event),
-       SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1,
-                     sst_mix_codec1_controls, sst_swm_mixer_event),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-       {"media0_in", NULL, "Compress Playback"},
-       {"media1_in", NULL, "Headset Playback"},
-       {"media2_in", NULL, "pcm0_out"},
-
-       {"media0_out mix 0", "media0_in Switch", "media0_in"},
-       {"media0_out mix 0", "media1_in Switch", "media1_in"},
-       {"media0_out mix 0", "media2_in Switch", "media2_in"},
-       {"media0_out mix 0", "media3_in Switch", "media3_in"},
-       {"media1_out mix 0", "media0_in Switch", "media0_in"},
-       {"media1_out mix 0", "media1_in Switch", "media1_in"},
-       {"media1_out mix 0", "media2_in Switch", "media2_in"},
-       {"media1_out mix 0", "media3_in Switch", "media3_in"},
-
-       {"media0_out", NULL, "media0_out mix 0"},
-       {"media1_out", NULL, "media1_out mix 0"},
-       {"pcm0_in", NULL, "media0_out"},
-       {"pcm1_in", NULL, "media1_out"},
-
-       {"Headset Capture", NULL, "pcm1_out"},
-       {"Headset Capture", NULL, "pcm2_out"},
-       {"pcm0_out", NULL, "pcm0_out mix 0"},
-       SST_SBA_MIXER_GRAPH_MAP("pcm0_out mix 0"),
-       {"pcm1_out", NULL, "pcm1_out mix 0"},
-       SST_SBA_MIXER_GRAPH_MAP("pcm1_out mix 0"),
-       {"pcm2_out", NULL, "pcm2_out mix 0"},
-       SST_SBA_MIXER_GRAPH_MAP("pcm2_out mix 0"),
-
-       {"media_loop1_in", NULL, "media_loop1_out"},
-       {"media_loop1_out", NULL, "media_loop1_out mix 0"},
-       SST_SBA_MIXER_GRAPH_MAP("media_loop1_out mix 0"),
-       {"media_loop2_in", NULL, "media_loop2_out"},
-       {"media_loop2_out", NULL, "media_loop2_out mix 0"},
-       SST_SBA_MIXER_GRAPH_MAP("media_loop2_out mix 0"),
-       {"sprot_loop_in", NULL, "sprot_loop_out"},
-       {"sprot_loop_out", NULL, "sprot_loop_out mix 0"},
-       SST_SBA_MIXER_GRAPH_MAP("sprot_loop_out mix 0"),
-
-       {"codec_out0", NULL, "codec_out0 mix 0"},
-       SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"),
-       {"codec_out1", NULL, "codec_out1 mix 0"},
-       SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"),
-
-};
-static const char * const slot_names[] = {
-       "none",
-       "slot 0", "slot 1", "slot 2", "slot 3",
-       "slot 4", "slot 5", "slot 6", "slot 7", /* not supported by FW */
-};
-
-static const char * const channel_names[] = {
-       "none",
-       "codec_out0_0", "codec_out0_1", "codec_out1_0", "codec_out1_1",
-       "codec_out2_0", "codec_out2_1", "codec_out3_0", "codec_out3_1", /* not supported by FW */
-};
-
-#define SST_INTERLEAVER(xpname, slot_name, slotno) \
-       SST_SSP_SLOT_CTL(xpname, "tx interleaver", slot_name, slotno, true, \
-                        channel_names, sst_slot_get, sst_slot_put)
-
-#define SST_DEINTERLEAVER(xpname, channel_name, channel_no) \
-       SST_SSP_SLOT_CTL(xpname, "rx deinterleaver", channel_name, channel_no, false, \
-                        slot_names, sst_slot_get, sst_slot_put)
-
-static const struct snd_kcontrol_new sst_slot_controls[] = {
-       SST_INTERLEAVER("codec_out", "slot 0", 0),
-       SST_INTERLEAVER("codec_out", "slot 1", 1),
-       SST_INTERLEAVER("codec_out", "slot 2", 2),
-       SST_INTERLEAVER("codec_out", "slot 3", 3),
-       SST_DEINTERLEAVER("codec_in", "codec_in0_0", 0),
-       SST_DEINTERLEAVER("codec_in", "codec_in0_1", 1),
-       SST_DEINTERLEAVER("codec_in", "codec_in1_0", 2),
-       SST_DEINTERLEAVER("codec_in", "codec_in1_1", 3),
-};
-
-/* Gain helper with min/max set */
-#define SST_GAIN(name, path_id, task_id, instance, gain_var)                           \
-       SST_GAIN_KCONTROLS(name, "Gain", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE,        \
-               SST_GAIN_TC_MIN, SST_GAIN_TC_MAX,                                       \
-               sst_gain_get, sst_gain_put,                                             \
-               SST_MODULE_ID_GAIN_CELL, path_id, instance, task_id,                    \
-               sst_gain_tlv_common, gain_var)
-
-#define SST_VOLUME(name, path_id, task_id, instance, gain_var)                         \
-       SST_GAIN_KCONTROLS(name, "Volume", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE,      \
-               SST_GAIN_TC_MIN, SST_GAIN_TC_MAX,                                       \
-               sst_gain_get, sst_gain_put,                                             \
-               SST_MODULE_ID_VOLUME, path_id, instance, task_id,                       \
-               sst_gain_tlv_common, gain_var)
-
-static struct sst_gain_value sst_gains[];
-
-static const struct snd_kcontrol_new sst_gain_controls[] = {
-       SST_GAIN("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[0]),
-       SST_GAIN("media1_in", SST_PATH_INDEX_MEDIA1_IN, SST_TASK_MMX, 0, &sst_gains[1]),
-       SST_GAIN("media2_in", SST_PATH_INDEX_MEDIA2_IN, SST_TASK_MMX, 0, &sst_gains[2]),
-       SST_GAIN("media3_in", SST_PATH_INDEX_MEDIA3_IN, SST_TASK_MMX, 0, &sst_gains[3]),
-
-       SST_GAIN("pcm0_in", SST_PATH_INDEX_PCM0_IN, SST_TASK_SBA, 0, &sst_gains[4]),
-       SST_GAIN("pcm1_in", SST_PATH_INDEX_PCM1_IN, SST_TASK_SBA, 0, &sst_gains[5]),
-       SST_GAIN("pcm1_out", SST_PATH_INDEX_PCM1_OUT, SST_TASK_SBA, 0, &sst_gains[6]),
-       SST_GAIN("pcm2_out", SST_PATH_INDEX_PCM2_OUT, SST_TASK_SBA, 0, &sst_gains[7]),
-
-       SST_GAIN("codec_in0", SST_PATH_INDEX_CODEC_IN0, SST_TASK_SBA, 0, &sst_gains[8]),
-       SST_GAIN("codec_in1", SST_PATH_INDEX_CODEC_IN1, SST_TASK_SBA, 0, &sst_gains[9]),
-       SST_GAIN("codec_out0", SST_PATH_INDEX_CODEC_OUT0, SST_TASK_SBA, 0, &sst_gains[10]),
-       SST_GAIN("codec_out1", SST_PATH_INDEX_CODEC_OUT1, SST_TASK_SBA, 0, &sst_gains[11]),
-       SST_GAIN("media_loop1_out", SST_PATH_INDEX_MEDIA_LOOP1_OUT, SST_TASK_SBA, 0, &sst_gains[12]),
-       SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]),
-       SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]),
-       SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]),
-};
-
-#define SST_GAIN_NUM_CONTROLS 3
-/* the SST_GAIN macro above will create three alsa controls for each
- * instance invoked, gain, mute and ramp duration, which use the same gain
- * cell sst_gain to keep track of data
- * To calculate number of gain cell instances we need to device by 3 in
- * below caulcation for gain cell memory.
- * This gets rid of static number and issues while adding new controls
- */
-static struct sst_gain_value sst_gains[ARRAY_SIZE(sst_gain_controls)/SST_GAIN_NUM_CONTROLS];
-
-static const struct snd_kcontrol_new sst_algo_controls[] = {
-       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
-                SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
-       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24,
-               SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
-       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP,
-               SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
-       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24,
-               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
-       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24,
-               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
-       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP,
-               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
-       SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT,
-               SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO),
-       SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR,
-               SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
-       SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR,
-               SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
-
-};
-
-static int sst_algo_control_init(struct device *dev)
-{
-       int i = 0;
-       struct sst_algo_control *bc;
-       /*allocate space to cache the algo parameters in the driver*/
-       for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) {
-               bc = (struct sst_algo_control *)sst_algo_controls[i].private_value;
-               bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL);
-               if (bc->params == NULL)
-                       return -ENOMEM;
-       }
-       return 0;
-}
-
-static bool is_sst_dapm_widget(struct snd_soc_dapm_widget *w)
-{
-       switch (w->id) {
-       case snd_soc_dapm_pga:
-       case snd_soc_dapm_aif_in:
-       case snd_soc_dapm_aif_out:
-       case snd_soc_dapm_input:
-       case snd_soc_dapm_output:
-       case snd_soc_dapm_mixer:
-               return true;
-       default:
-               return false;
-       }
-}
-
-/**
- * sst_send_pipe_gains - send gains for the front-end DAIs
- *
- * The gains in the pipes connected to the front-ends are muted/unmuted
- * automatically via the digital_mute() DAPM callback. This function sends the
- * gains for the front-end pipes.
- */
-int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
-{
-       struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
-       struct snd_soc_dapm_widget *w;
-       struct snd_soc_dapm_path *p = NULL;
-
-       dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream);
-
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dev_dbg(dai->dev, "Stream name=%s\n",
-                               dai->playback_widget->name);
-               w = dai->playback_widget;
-               list_for_each_entry(p, &w->sinks, list_source) {
-                       if (p->connected && !p->connected(w, p->sink))
-                               continue;
-
-                       if (p->connect && p->sink->power &&
-                                       is_sst_dapm_widget(p->sink)) {
-                               struct sst_ids *ids = p->sink->priv;
-
-                               dev_dbg(dai->dev, "send gains for widget=%s\n",
-                                               p->sink->name);
-                               mutex_lock(&drv->lock);
-                               sst_set_pipe_gain(ids, drv, mute);
-                               mutex_unlock(&drv->lock);
-                       }
-               }
-       } else {
-               dev_dbg(dai->dev, "Stream name=%s\n",
-                               dai->capture_widget->name);
-               w = dai->capture_widget;
-               list_for_each_entry(p, &w->sources, list_sink) {
-                       if (p->connected && !p->connected(w, p->sink))
-                               continue;
-
-                       if (p->connect &&  p->source->power &&
-                                       is_sst_dapm_widget(p->source)) {
-                               struct sst_ids *ids = p->source->priv;
-
-                               dev_dbg(dai->dev, "send gain for widget=%s\n",
-                                               p->source->name);
-                               mutex_lock(&drv->lock);
-                               sst_set_pipe_gain(ids, drv, mute);
-                               mutex_unlock(&drv->lock);
-                       }
-               }
-       }
-       return 0;
-}
-
-/**
- * sst_fill_module_list - populate the list of modules/gains for a pipe
- *
- *
- * Fills the widget pointer in the kcontrol private data, and also fills the
- * kcontrol pointer in the widget private data.
- *
- * Widget pointer is used to send the algo/gain in the .put() handler if the
- * widget is powerd on.
- *
- * Kcontrol pointer is used to send the algo/gain in the widget power ON/OFF
- * event handler. Each widget (pipe) has multiple algos stored in the algo_list.
- */
-static int sst_fill_module_list(struct snd_kcontrol *kctl,
-        struct snd_soc_dapm_widget *w, int type)
-{
-       struct sst_module *module = NULL;
-       struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
-       struct sst_ids *ids = w->priv;
-       int ret = 0;
-
-       module = devm_kzalloc(c->dev, sizeof(*module), GFP_KERNEL);
-       if (!module)
-               return -ENOMEM;
-
-       if (type == SST_MODULE_GAIN) {
-               struct sst_gain_mixer_control *mc = (void *)kctl->private_value;
-
-               mc->w = w;
-               module->kctl = kctl;
-               list_add_tail(&module->node, &ids->gain_list);
-       } else if (type == SST_MODULE_ALGO) {
-               struct sst_algo_control *bc = (void *)kctl->private_value;
-
-               bc->w = w;
-               module->kctl = kctl;
-               list_add_tail(&module->node, &ids->algo_list);
-       } else {
-               dev_err(c->dev, "invoked for unknown type %d module %s",
-                               type, kctl->id.name);
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-/**
- * sst_fill_widget_module_info - fill list of gains/algos for the pipe
- * @widget:    pipe modelled as a DAPM widget
- *
- * Fill the list of gains/algos for the widget by looking at all the card
- * controls and comparing the name of the widget with the first part of control
- * name. First part of control name contains the pipe name (widget name).
- */
-static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w,
-       struct snd_soc_platform *platform)
-{
-       struct snd_kcontrol *kctl;
-       int index, ret = 0;
-       struct snd_card *card = platform->component.card->snd_card;
-       char *idx;
-
-       down_read(&card->controls_rwsem);
-
-       list_for_each_entry(kctl, &card->controls, list) {
-               idx = strstr(kctl->id.name, " ");
-               if (idx == NULL)
-                       continue;
-               index  = strlen(kctl->id.name) - strlen(idx);
-
-               if (strstr(kctl->id.name, "Volume") &&
-                   !strncmp(kctl->id.name, w->name, index))
-                       ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN);
-
-               else if (strstr(kctl->id.name, "params") &&
-                        !strncmp(kctl->id.name, w->name, index))
-                       ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO);
-
-               else if (strstr(kctl->id.name, "Switch") &&
-                        !strncmp(kctl->id.name, w->name, index) &&
-                        strstr(kctl->id.name, "Gain")) {
-                       struct sst_gain_mixer_control *mc =
-                                               (void *)kctl->private_value;
-
-                       mc->w = w;
-
-               } else if (strstr(kctl->id.name, "interleaver") &&
-                        !strncmp(kctl->id.name, w->name, index)) {
-                       struct sst_enum *e = (void *)kctl->private_value;
-
-                       e->w = w;
-
-               } else if (strstr(kctl->id.name, "deinterleaver") &&
-                        !strncmp(kctl->id.name, w->name, index)) {
-
-                       struct sst_enum *e = (void *)kctl->private_value;
-
-                       e->w = w;
-               }
-
-               if (ret < 0) {
-                       up_read(&card->controls_rwsem);
-                       return ret;
-               }
-       }
-
-       up_read(&card->controls_rwsem);
-       return 0;
-}
-
-/**
- * sst_fill_linked_widgets - fill the parent pointer for the linked widget
- */
-static void sst_fill_linked_widgets(struct snd_soc_platform *platform,
-                                               struct sst_ids *ids)
-{
-       struct snd_soc_dapm_widget *w;
-       unsigned int len = strlen(ids->parent_wname);
-
-       list_for_each_entry(w, &platform->component.card->widgets, list) {
-               if (!strncmp(ids->parent_wname, w->name, len)) {
-                       ids->parent_w = w;
-                       break;
-               }
-       }
-}
-
-/**
- * sst_map_modules_to_pipe - fill algo/gains list for all pipes
- */
-static int sst_map_modules_to_pipe(struct snd_soc_platform *platform)
-{
-       struct snd_soc_dapm_widget *w;
-       int ret = 0;
-
-       list_for_each_entry(w, &platform->component.card->widgets, list) {
-               if (is_sst_dapm_widget(w) && (w->priv)) {
-                       struct sst_ids *ids = w->priv;
-
-                       dev_dbg(platform->dev, "widget type=%d name=%s\n",
-                                       w->id, w->name);
-                       INIT_LIST_HEAD(&ids->algo_list);
-                       INIT_LIST_HEAD(&ids->gain_list);
-                       ret = sst_fill_widget_module_info(w, platform);
-
-                       if (ret < 0)
-                               return ret;
-
-                       /* fill linked widgets */
-                       if (ids->parent_wname !=  NULL)
-                               sst_fill_linked_widgets(platform, ids);
-               }
-       }
-       return 0;
-}
-
-int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
-{
-       int i, ret = 0;
-       struct snd_soc_dapm_context *dapm =
-                       snd_soc_component_get_dapm(&platform->component);
-       struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
-       unsigned int gains = ARRAY_SIZE(sst_gain_controls)/3;
-
-       drv->byte_stream = devm_kzalloc(platform->dev,
-                                       SST_MAX_BIN_BYTES, GFP_KERNEL);
-       if (!drv->byte_stream)
-               return -ENOMEM;
-
-       snd_soc_dapm_new_controls(dapm, sst_dapm_widgets,
-                       ARRAY_SIZE(sst_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon,
-                       ARRAY_SIZE(intercon));
-       snd_soc_dapm_new_widgets(dapm->card);
-
-       for (i = 0; i < gains; i++) {
-               sst_gains[i].mute = SST_GAIN_MUTE_DEFAULT;
-               sst_gains[i].l_gain = SST_GAIN_VOLUME_DEFAULT;
-               sst_gains[i].r_gain = SST_GAIN_VOLUME_DEFAULT;
-               sst_gains[i].ramp_duration = SST_GAIN_RAMP_DURATION_DEFAULT;
-       }
-
-       ret = snd_soc_add_platform_controls(platform, sst_gain_controls,
-                       ARRAY_SIZE(sst_gain_controls));
-       if (ret)
-               return ret;
-
-       /* Initialize algo control params */
-       ret = sst_algo_control_init(platform->dev);
-       if (ret)
-               return ret;
-       ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
-                       ARRAY_SIZE(sst_algo_controls));
-       if (ret)
-               return ret;
-
-       ret = snd_soc_add_platform_controls(platform, sst_slot_controls,
-                       ARRAY_SIZE(sst_slot_controls));
-       if (ret)
-               return ret;
-
-       ret = sst_map_modules_to_pipe(platform);
-
-       return ret;
-}
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h
deleted file mode 100644 (file)
index dfebfdd..0000000
+++ /dev/null
@@ -1,870 +0,0 @@
-/*
- *  sst-atom-controls.h - Intel MID Platform driver header file
- *
- *  Copyright (C) 2013-14 Intel Corp
- *  Author: Ramesh Babu <ramesh.babu.koul@intel.com>
- *     Omair M Abdullah <omair.m.abdullah@intel.com>
- *     Samreen Nilofer <samreen.nilofer@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- */
-
-#ifndef __SST_ATOM_CONTROLS_H__
-#define __SST_ATOM_CONTROLS_H__
-
-#include <sound/soc.h>
-#include <sound/tlv.h>
-
-enum {
-       MERR_DPCM_AUDIO = 0,
-       MERR_DPCM_COMPR,
-};
-
-/* define a bit for each mixer input */
-#define SST_MIX_IP(x)          (x)
-
-#define SST_IP_CODEC0          SST_MIX_IP(2)
-#define SST_IP_CODEC1          SST_MIX_IP(3)
-#define SST_IP_LOOP0           SST_MIX_IP(4)
-#define SST_IP_LOOP1           SST_MIX_IP(5)
-#define SST_IP_LOOP2           SST_MIX_IP(6)
-#define SST_IP_PROBE           SST_MIX_IP(7)
-#define SST_IP_VOIP            SST_MIX_IP(12)
-#define SST_IP_PCM0            SST_MIX_IP(13)
-#define SST_IP_PCM1            SST_MIX_IP(14)
-#define SST_IP_MEDIA0          SST_MIX_IP(17)
-#define SST_IP_MEDIA1          SST_MIX_IP(18)
-#define SST_IP_MEDIA2          SST_MIX_IP(19)
-#define SST_IP_MEDIA3          SST_MIX_IP(20)
-
-#define SST_IP_LAST            SST_IP_MEDIA3
-
-#define SST_SWM_INPUT_COUNT    (SST_IP_LAST + 1)
-#define SST_CMD_SWM_MAX_INPUTS 6
-
-#define SST_PATH_ID_SHIFT      8
-#define SST_DEFAULT_LOCATION_ID        0xFFFF
-#define SST_DEFAULT_CELL_NBR   0xFF
-#define SST_DEFAULT_MODULE_ID  0xFFFF
-
-/*
- * Audio DSP Path Ids. Specified by the audio DSP FW
- */
-enum sst_path_index {
-       SST_PATH_INDEX_CODEC_OUT0               = (0x02 << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_CODEC_OUT1               = (0x03 << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_SPROT_LOOP_OUT           = (0x04 << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_MEDIA_LOOP1_OUT          = (0x05 << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_MEDIA_LOOP2_OUT          = (0x06 << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_VOIP_OUT                 = (0x0C << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_PCM0_OUT                 = (0x0D << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_PCM1_OUT                 = (0x0E << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_PCM2_OUT                 = (0x0F << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_MEDIA0_OUT               = (0x12 << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_MEDIA1_OUT               = (0x13 << SST_PATH_ID_SHIFT),
-
-
-       /* Start of input paths */
-       SST_PATH_INDEX_CODEC_IN0                = (0x82 << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_CODEC_IN1                = (0x83 << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_SPROT_LOOP_IN            = (0x84 << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_MEDIA_LOOP1_IN           = (0x85 << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_MEDIA_LOOP2_IN           = (0x86 << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_VOIP_IN                  = (0x8C << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_PCM0_IN                  = (0x8D << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_PCM1_IN                  = (0x8E << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_MEDIA0_IN                = (0x8F << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_MEDIA1_IN                = (0x90 << SST_PATH_ID_SHIFT),
-       SST_PATH_INDEX_MEDIA2_IN                = (0x91 << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_MEDIA3_IN                = (0x9C << SST_PATH_ID_SHIFT),
-
-       SST_PATH_INDEX_RESERVED                 = (0xFF << SST_PATH_ID_SHIFT),
-};
-
-/*
- * path IDs
- */
-enum sst_swm_inputs {
-       SST_SWM_IN_CODEC0       = (SST_PATH_INDEX_CODEC_IN0       | SST_DEFAULT_CELL_NBR),
-       SST_SWM_IN_CODEC1       = (SST_PATH_INDEX_CODEC_IN1       | SST_DEFAULT_CELL_NBR),
-       SST_SWM_IN_SPROT_LOOP   = (SST_PATH_INDEX_SPROT_LOOP_IN   | SST_DEFAULT_CELL_NBR),
-       SST_SWM_IN_MEDIA_LOOP1  = (SST_PATH_INDEX_MEDIA_LOOP1_IN  | SST_DEFAULT_CELL_NBR),
-       SST_SWM_IN_MEDIA_LOOP2  = (SST_PATH_INDEX_MEDIA_LOOP2_IN  | SST_DEFAULT_CELL_NBR),
-       SST_SWM_IN_VOIP         = (SST_PATH_INDEX_VOIP_IN         | SST_DEFAULT_CELL_NBR),
-       SST_SWM_IN_PCM0         = (SST_PATH_INDEX_PCM0_IN         | SST_DEFAULT_CELL_NBR),
-       SST_SWM_IN_PCM1         = (SST_PATH_INDEX_PCM1_IN         | SST_DEFAULT_CELL_NBR),
-       SST_SWM_IN_MEDIA0       = (SST_PATH_INDEX_MEDIA0_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
-       SST_SWM_IN_MEDIA1       = (SST_PATH_INDEX_MEDIA1_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
-       SST_SWM_IN_MEDIA2       = (SST_PATH_INDEX_MEDIA2_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
-       SST_SWM_IN_MEDIA3       = (SST_PATH_INDEX_MEDIA3_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
-       SST_SWM_IN_END          = (SST_PATH_INDEX_RESERVED        | SST_DEFAULT_CELL_NBR)
-};
-
-/*
- * path IDs
- */
-enum sst_swm_outputs {
-       SST_SWM_OUT_CODEC0      = (SST_PATH_INDEX_CODEC_OUT0      | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_CODEC1      = (SST_PATH_INDEX_CODEC_OUT1      | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_SPROT_LOOP  = (SST_PATH_INDEX_SPROT_LOOP_OUT  | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_VOIP        = (SST_PATH_INDEX_VOIP_OUT        | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_PCM0        = (SST_PATH_INDEX_PCM0_OUT        | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_PCM1        = (SST_PATH_INDEX_PCM1_OUT        | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_PCM2        = (SST_PATH_INDEX_PCM2_OUT        | SST_DEFAULT_CELL_NBR),
-       SST_SWM_OUT_MEDIA0      = (SST_PATH_INDEX_MEDIA0_OUT      | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
-       SST_SWM_OUT_MEDIA1      = (SST_PATH_INDEX_MEDIA1_OUT      | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
-       SST_SWM_OUT_END         = (SST_PATH_INDEX_RESERVED        | SST_DEFAULT_CELL_NBR),
-};
-
-enum sst_ipc_msg {
-       SST_IPC_IA_CMD = 1,
-       SST_IPC_IA_SET_PARAMS,
-       SST_IPC_IA_GET_PARAMS,
-};
-
-enum sst_cmd_type {
-       SST_CMD_BYTES_SET = 1,
-       SST_CMD_BYTES_GET = 2,
-};
-
-enum sst_task {
-       SST_TASK_SBA = 1,
-       SST_TASK_MMX,
-};
-
-enum sst_type {
-       SST_TYPE_CMD = 1,
-       SST_TYPE_PARAMS,
-};
-
-enum sst_flag {
-       SST_FLAG_BLOCKED = 1,
-       SST_FLAG_NONBLOCK,
-};
-
-/*
- * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command
- */
-enum sst_gain_index {
-       /* GAIN IDs for SB task start here */
-       SST_GAIN_INDEX_CODEC_OUT0,
-       SST_GAIN_INDEX_CODEC_OUT1,
-       SST_GAIN_INDEX_CODEC_IN0,
-       SST_GAIN_INDEX_CODEC_IN1,
-
-       SST_GAIN_INDEX_SPROT_LOOP_OUT,
-       SST_GAIN_INDEX_MEDIA_LOOP1_OUT,
-       SST_GAIN_INDEX_MEDIA_LOOP2_OUT,
-
-       SST_GAIN_INDEX_PCM0_IN_LEFT,
-       SST_GAIN_INDEX_PCM0_IN_RIGHT,
-
-       SST_GAIN_INDEX_PCM1_OUT_LEFT,
-       SST_GAIN_INDEX_PCM1_OUT_RIGHT,
-       SST_GAIN_INDEX_PCM1_IN_LEFT,
-       SST_GAIN_INDEX_PCM1_IN_RIGHT,
-       SST_GAIN_INDEX_PCM2_OUT_LEFT,
-
-       SST_GAIN_INDEX_PCM2_OUT_RIGHT,
-       SST_GAIN_INDEX_VOIP_OUT,
-       SST_GAIN_INDEX_VOIP_IN,
-
-       /* Gain IDs for MMX task start here */
-       SST_GAIN_INDEX_MEDIA0_IN_LEFT,
-       SST_GAIN_INDEX_MEDIA0_IN_RIGHT,
-       SST_GAIN_INDEX_MEDIA1_IN_LEFT,
-       SST_GAIN_INDEX_MEDIA1_IN_RIGHT,
-
-       SST_GAIN_INDEX_MEDIA2_IN_LEFT,
-       SST_GAIN_INDEX_MEDIA2_IN_RIGHT,
-
-       SST_GAIN_INDEX_GAIN_END
-};
-
-/*
- * Audio DSP module IDs specified by FW spec
- * TODO: Update with all modules
- */
-enum sst_module_id {
-       SST_MODULE_ID_PCM                 = 0x0001,
-       SST_MODULE_ID_MP3                 = 0x0002,
-       SST_MODULE_ID_MP24                = 0x0003,
-       SST_MODULE_ID_AAC                 = 0x0004,
-       SST_MODULE_ID_AACP                = 0x0005,
-       SST_MODULE_ID_EAACP               = 0x0006,
-       SST_MODULE_ID_WMA9                = 0x0007,
-       SST_MODULE_ID_WMA10               = 0x0008,
-       SST_MODULE_ID_WMA10P              = 0x0009,
-       SST_MODULE_ID_RA                  = 0x000A,
-       SST_MODULE_ID_DDAC3               = 0x000B,
-       SST_MODULE_ID_TRUE_HD             = 0x000C,
-       SST_MODULE_ID_HD_PLUS             = 0x000D,
-
-       SST_MODULE_ID_SRC                 = 0x0064,
-       SST_MODULE_ID_DOWNMIX             = 0x0066,
-       SST_MODULE_ID_GAIN_CELL           = 0x0067,
-       SST_MODULE_ID_SPROT               = 0x006D,
-       SST_MODULE_ID_BASS_BOOST          = 0x006E,
-       SST_MODULE_ID_STEREO_WDNG         = 0x006F,
-       SST_MODULE_ID_AV_REMOVAL          = 0x0070,
-       SST_MODULE_ID_MIC_EQ              = 0x0071,
-       SST_MODULE_ID_SPL                 = 0x0072,
-       SST_MODULE_ID_ALGO_VTSV           = 0x0073,
-       SST_MODULE_ID_NR                  = 0x0076,
-       SST_MODULE_ID_BWX                 = 0x0077,
-       SST_MODULE_ID_DRP                 = 0x0078,
-       SST_MODULE_ID_MDRP                = 0x0079,
-
-       SST_MODULE_ID_ANA                 = 0x007A,
-       SST_MODULE_ID_AEC                 = 0x007B,
-       SST_MODULE_ID_NR_SNS              = 0x007C,
-       SST_MODULE_ID_SER                 = 0x007D,
-       SST_MODULE_ID_AGC                 = 0x007E,
-
-       SST_MODULE_ID_CNI                 = 0x007F,
-       SST_MODULE_ID_CONTEXT_ALGO_AWARE  = 0x0080,
-       SST_MODULE_ID_FIR_24              = 0x0081,
-       SST_MODULE_ID_IIR_24              = 0x0082,
-
-       SST_MODULE_ID_ASRC                = 0x0083,
-       SST_MODULE_ID_TONE_GEN            = 0x0084,
-       SST_MODULE_ID_BMF                 = 0x0086,
-       SST_MODULE_ID_EDL                 = 0x0087,
-       SST_MODULE_ID_GLC                 = 0x0088,
-
-       SST_MODULE_ID_FIR_16              = 0x0089,
-       SST_MODULE_ID_IIR_16              = 0x008A,
-       SST_MODULE_ID_DNR                 = 0x008B,
-
-       SST_MODULE_ID_VIRTUALIZER         = 0x008C,
-       SST_MODULE_ID_VISUALIZATION       = 0x008D,
-       SST_MODULE_ID_LOUDNESS_OPTIMIZER  = 0x008E,
-       SST_MODULE_ID_REVERBERATION       = 0x008F,
-
-       SST_MODULE_ID_CNI_TX              = 0x0090,
-       SST_MODULE_ID_REF_LINE            = 0x0091,
-       SST_MODULE_ID_VOLUME              = 0x0092,
-       SST_MODULE_ID_FILT_DCR            = 0x0094,
-       SST_MODULE_ID_SLV                 = 0x009A,
-       SST_MODULE_ID_NLF                 = 0x009B,
-       SST_MODULE_ID_TNR                 = 0x009C,
-       SST_MODULE_ID_WNR                 = 0x009D,
-
-       SST_MODULE_ID_LOG                 = 0xFF00,
-
-       SST_MODULE_ID_TASK                = 0xFFFF,
-};
-
-enum sst_cmd {
-       SBA_IDLE                = 14,
-       SBA_VB_SET_SPEECH_PATH  = 26,
-       MMX_SET_GAIN            = 33,
-       SBA_VB_SET_GAIN         = 33,
-       FBA_VB_RX_CNI           = 35,
-       MMX_SET_GAIN_TIMECONST  = 36,
-       SBA_VB_SET_TIMECONST    = 36,
-       SBA_VB_START            = 85,
-       SBA_SET_SWM             = 114,
-       SBA_SET_MDRP            = 116,
-       SBA_HW_SET_SSP          = 117,
-       SBA_SET_MEDIA_LOOP_MAP  = 118,
-       SBA_SET_MEDIA_PATH      = 119,
-       MMX_SET_MEDIA_PATH      = 119,
-       SBA_VB_LPRO             = 126,
-       SBA_VB_SET_FIR          = 128,
-       SBA_VB_SET_IIR          = 129,
-       SBA_SET_SSP_SLOT_MAP    = 130,
-};
-
-enum sst_dsp_switch {
-       SST_SWITCH_OFF = 0,
-       SST_SWITCH_ON = 3,
-};
-
-enum sst_path_switch {
-       SST_PATH_OFF = 0,
-       SST_PATH_ON = 1,
-};
-
-enum sst_swm_state {
-       SST_SWM_OFF = 0,
-       SST_SWM_ON = 3,
-};
-
-#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id)          do {    \
-               dst.location_id.p.cell_nbr_idx = (cell_idx);            \
-               dst.location_id.p.path_id = (pipe_id);                  \
-       } while (0)
-#define SST_FILL_LOCATION_ID(dst, loc_id)                              (\
-       dst.location_id.f = (loc_id))
-#define SST_FILL_MODULE_ID(dst, mod_id)                                        (\
-       dst.module_id = (mod_id))
-
-#define SST_FILL_DESTINATION1(dst, id)                         do {    \
-               SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF);               \
-               SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16);     \
-       } while (0)
-#define SST_FILL_DESTINATION2(dst, loc_id, mod_id)             do {    \
-               SST_FILL_LOCATION_ID(dst, loc_id);                      \
-               SST_FILL_MODULE_ID(dst, mod_id);                        \
-       } while (0)
-#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id)  do {    \
-               SST_FILL_LOCATION_IDS(dst, cell_idx, path_id);          \
-               SST_FILL_MODULE_ID(dst, mod_id);                        \
-       } while (0)
-
-#define SST_FILL_DESTINATION(level, dst, ...)                          \
-       SST_FILL_DESTINATION##level(dst, __VA_ARGS__)
-#define SST_FILL_DEFAULT_DESTINATION(dst)                              \
-       SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID)
-
-struct sst_destination_id {
-       union sst_location_id {
-               struct {
-                       u8 cell_nbr_idx;        /* module index */
-                       u8 path_id;             /* pipe_id */
-               } __packed      p;              /* part */
-               u16             f;              /* full */
-       } __packed location_id;
-       u16        module_id;
-} __packed;
-struct sst_dsp_header {
-       struct sst_destination_id dst;
-       u16 command_id;
-       u16 length;
-} __packed;
-
-/*
- *
- * Common Commands
- *
- */
-struct sst_cmd_generic {
-       struct sst_dsp_header header;
-} __packed;
-
-struct swm_input_ids {
-       struct sst_destination_id input_id;
-} __packed;
-
-struct sst_cmd_set_swm {
-       struct sst_dsp_header header;
-       struct sst_destination_id output_id;
-       u16    switch_state;
-       u16    nb_inputs;
-       struct swm_input_ids input[SST_CMD_SWM_MAX_INPUTS];
-} __packed;
-
-struct sst_cmd_set_media_path {
-       struct sst_dsp_header header;
-       u16    switch_state;
-} __packed;
-
-struct pcm_cfg {
-               u8 s_length:2;
-               u8 rate:3;
-               u8 format:3;
-} __packed;
-
-struct sst_cmd_set_speech_path {
-       struct sst_dsp_header header;
-       u16    switch_state;
-       struct {
-               u16 rsvd:8;
-               struct pcm_cfg cfg;
-       } config;
-} __packed;
-
-struct gain_cell {
-       struct sst_destination_id dest;
-       s16 cell_gain_left;
-       s16 cell_gain_right;
-       u16 gain_time_constant;
-} __packed;
-
-#define NUM_GAIN_CELLS 1
-struct sst_cmd_set_gain_dual {
-       struct sst_dsp_header header;
-       u16    gain_cell_num;
-       struct gain_cell cell_gains[NUM_GAIN_CELLS];
-} __packed;
-struct sst_cmd_set_params {
-       struct sst_destination_id dst;
-       u16 command_id;
-       char params[0];
-} __packed;
-
-
-struct sst_cmd_sba_vb_start {
-       struct sst_dsp_header header;
-} __packed;
-
-union sba_media_loop_params {
-       struct {
-               u16 rsvd:8;
-               struct pcm_cfg cfg;
-       } part;
-       u16 full;
-} __packed;
-
-struct sst_cmd_sba_set_media_loop_map {
-       struct  sst_dsp_header header;
-       u16     switch_state;
-       union   sba_media_loop_params param;
-       u16     map;
-} __packed;
-
-struct sst_cmd_tone_stop {
-       struct  sst_dsp_header header;
-       u16     switch_state;
-} __packed;
-
-enum sst_ssp_mode {
-       SSP_MODE_MASTER = 0,
-       SSP_MODE_SLAVE = 1,
-};
-
-enum sst_ssp_pcm_mode {
-       SSP_PCM_MODE_NORMAL = 0,
-       SSP_PCM_MODE_NETWORK = 1,
-};
-
-enum sst_ssp_duplex {
-       SSP_DUPLEX = 0,
-       SSP_RX = 1,
-       SSP_TX = 2,
-};
-
-enum sst_ssp_fs_frequency {
-       SSP_FS_8_KHZ = 0,
-       SSP_FS_16_KHZ = 1,
-       SSP_FS_44_1_KHZ = 2,
-       SSP_FS_48_KHZ = 3,
-};
-
-enum sst_ssp_fs_polarity {
-       SSP_FS_ACTIVE_LOW = 0,
-       SSP_FS_ACTIVE_HIGH = 1,
-};
-
-enum sst_ssp_protocol {
-       SSP_MODE_PCM = 0,
-       SSP_MODE_I2S = 1,
-};
-
-enum sst_ssp_port_id {
-       SSP_MODEM = 0,
-       SSP_BT = 1,
-       SSP_FM = 2,
-       SSP_CODEC = 3,
-};
-
-struct sst_cmd_sba_hw_set_ssp {
-       struct sst_dsp_header header;
-       u16 selection;                  /* 0:SSP0(def), 1:SSP1, 2:SSP2 */
-
-       u16 switch_state;
-
-       u16 nb_bits_per_slots:6;        /* 0-32 bits, 24 (def) */
-       u16 nb_slots:4;                 /* 0-8: slots per frame  */
-       u16 mode:3;                     /* 0:Master, 1: Slave  */
-       u16 duplex:3;
-
-       u16 active_tx_slot_map:8;       /* Bit map, 0:off, 1:on */
-       u16 reserved1:8;
-
-       u16 active_rx_slot_map:8;       /* Bit map 0: Off, 1:On */
-       u16 reserved2:8;
-
-       u16 frame_sync_frequency;
-
-       u16 frame_sync_polarity:8;
-       u16 data_polarity:8;
-
-       u16 frame_sync_width;           /* 1 to N clocks */
-       u16 ssp_protocol:8;
-       u16 start_delay:8;              /* Start delay in terms of clock ticks */
-} __packed;
-
-#define SST_MAX_TDM_SLOTS 8
-
-struct sst_param_sba_ssp_slot_map {
-       struct sst_dsp_header header;
-
-       u16 param_id;
-       u16 param_len;
-       u16 ssp_index;
-
-       u8 rx_slot_map[SST_MAX_TDM_SLOTS];
-       u8 tx_slot_map[SST_MAX_TDM_SLOTS];
-} __packed;
-
-enum {
-       SST_PROBE_EXTRACTOR = 0,
-       SST_PROBE_INJECTOR = 1,
-};
-
-/**** widget defines *****/
-
-#define SST_MODULE_GAIN 1
-#define SST_MODULE_ALGO 2
-
-#define SST_FMT_MONO 0
-#define SST_FMT_STEREO 3
-
-/* physical SSP numbers */
-enum {
-       SST_SSP0 = 0,
-       SST_SSP1,
-       SST_SSP2,
-       SST_SSP_LAST = SST_SSP2,
-};
-
-#define SST_NUM_SSPS           (SST_SSP_LAST + 1)      /* physical SSPs */
-#define SST_MAX_SSP_MUX                2                       /* single SSP muxed between pipes */
-#define SST_MAX_SSP_DOMAINS    2                       /* domains present in each pipe */
-
-struct sst_module {
-       struct snd_kcontrol *kctl;
-       struct list_head node;
-};
-
-struct sst_ssp_config {
-       u8 ssp_id;
-       u8 bits_per_slot;
-       u8 slots;
-       u8 ssp_mode;
-       u8 pcm_mode;
-       u8 duplex;
-       u8 ssp_protocol;
-       u8 fs_frequency;
-       u8 active_slot_map;
-       u8 start_delay;
-       u16 fs_width;
-};
-
-struct sst_ssp_cfg {
-       const u8 ssp_number;
-       const int *mux_shift;
-       const int (*domain_shift)[SST_MAX_SSP_MUX];
-       const struct sst_ssp_config (*ssp_config)[SST_MAX_SSP_MUX][SST_MAX_SSP_DOMAINS];
-};
-
-struct sst_ids {
-       u16 location_id;
-       u16 module_id;
-       u8  task_id;
-       u8  format;
-       u8  reg;
-       const char *parent_wname;
-       struct snd_soc_dapm_widget *parent_w;
-       struct list_head algo_list;
-       struct list_head gain_list;
-       const struct sst_pcm_format *pcm_fmt;
-};
-
-
-#define SST_AIF_IN(wname, wevent)                                                      \
-{      .id = snd_soc_dapm_aif_in, .name = wname, .sname = NULL,                        \
-       .reg = SND_SOC_NOPM, .shift = 0,                                        \
-       .on_val = 1, .off_val = 0,                                                      \
-       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
-       .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 }            \
-}
-
-#define SST_AIF_OUT(wname, wevent)                                                     \
-{      .id = snd_soc_dapm_aif_out, .name = wname, .sname = NULL,                       \
-       .reg = SND_SOC_NOPM, .shift = 0,                                                \
-       .on_val = 1, .off_val = 0,                                                      \
-       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
-       .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 }            \
-}
-
-#define SST_INPUT(wname, wevent)                                                       \
-{      .id = snd_soc_dapm_input, .name = wname, .sname = NULL,                         \
-       .reg = SND_SOC_NOPM, .shift = 0,                                                \
-       .on_val = 1, .off_val = 0,                                                      \
-       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
-       .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 }            \
-}
-
-#define SST_OUTPUT(wname, wevent)                                                      \
-{      .id = snd_soc_dapm_output, .name = wname, .sname = NULL,                        \
-       .reg = SND_SOC_NOPM, .shift = 0,                                                \
-       .on_val = 1, .off_val = 0,                                                      \
-       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
-       .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 }            \
-}
-
-#define SST_DAPM_OUTPUT(wname, wloc_id, wtask_id, wformat, wevent)                      \
-{      .id = snd_soc_dapm_output, .name = wname, .sname = NULL,                        \
-       .reg = SND_SOC_NOPM, .shift = 0,                                                \
-       .on_val = 1, .off_val = 0,                                                      \
-       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD,   \
-       .priv = (void *)&(struct sst_ids) { .location_id = wloc_id, .task_id = wtask_id,\
-                                               .pcm_fmt = wformat, }                   \
-}
-
-#define SST_PATH(wname, wtask, wloc_id, wevent, wflags)                                        \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0,         \
-       .kcontrol_news = NULL, .num_kcontrols = 0,                              \
-       .on_val = 1, .off_val = 0,                                                      \
-       .event = wevent, .event_flags = wflags,                                         \
-       .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, } \
-}
-
-#define SST_LINKED_PATH(wname, wtask, wloc_id, linked_wname, wevent, wflags)           \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0,         \
-       .kcontrol_news = NULL, .num_kcontrols = 0,                              \
-       .on_val = 1, .off_val = 0,                                                      \
-       .event = wevent, .event_flags = wflags,                                         \
-       .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id,   \
-                                       .parent_wname = linked_wname}                   \
-}
-
-#define SST_PATH_MEDIA_LOOP(wname, wtask, wloc_id, wformat, wevent, wflags)             \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0,         \
-       .kcontrol_news = NULL, .num_kcontrols = 0,                         \
-       .event = wevent, .event_flags = wflags,                                         \
-       .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id,   \
-                                           .format = wformat,}                         \
-}
-
-/* output is triggered before input */
-#define SST_PATH_INPUT(name, task_id, loc_id, event)                                   \
-       SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
-
-#define SST_PATH_LINKED_INPUT(name, task_id, loc_id, linked_wname, event)              \
-       SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event,                     \
-                                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
-
-#define SST_PATH_OUTPUT(name, task_id, loc_id, event)                                  \
-       SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
-
-#define SST_PATH_LINKED_OUTPUT(name, task_id, loc_id, linked_wname, event)             \
-       SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event,                     \
-                                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
-
-#define SST_PATH_MEDIA_LOOP_OUTPUT(name, task_id, loc_id, format, event)               \
-       SST_PATH_MEDIA_LOOP(name, task_id, loc_id, format, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
-
-
-#define SST_SWM_MIXER(wname, wreg, wtask, wloc_id, wcontrols, wevent)                  \
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = SND_SOC_NOPM, .shift = 0,       \
-       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols),\
-       .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD |  \
-                                       SND_SOC_DAPM_POST_REG,                          \
-       .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id,   \
-                                           .reg = wreg }                               \
-}
-
-enum sst_gain_kcontrol_type {
-       SST_GAIN_TLV,
-       SST_GAIN_MUTE,
-       SST_GAIN_RAMP_DURATION,
-};
-
-struct sst_gain_mixer_control {
-       bool stereo;
-       enum sst_gain_kcontrol_type type;
-       struct sst_gain_value *gain_val;
-       int max;
-       int min;
-       u16 instance_id;
-       u16 module_id;
-       u16 pipe_id;
-       u16 task_id;
-       char pname[44];
-       struct snd_soc_dapm_widget *w;
-};
-
-struct sst_gain_value {
-       u16 ramp_duration;
-       s16 l_gain;
-       s16 r_gain;
-       bool mute;
-};
-#define SST_GAIN_VOLUME_DEFAULT                (-1440)
-#define SST_GAIN_RAMP_DURATION_DEFAULT 5 /* timeconstant */
-#define SST_GAIN_MUTE_DEFAULT          true
-
-#define SST_GAIN_KCONTROL_TLV(xname, xhandler_get, xhandler_put, \
-                             xmod, xpipe, xinstance, xtask, tlv_array, xgain_val, \
-                             xmin, xmax, xpname) \
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
-                 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-       .tlv.p = (tlv_array), \
-       .info = sst_gain_ctl_info,\
-       .get = xhandler_get, .put = xhandler_put, \
-       .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
-       { .stereo = true, .max = xmax, .min = xmin, .type = SST_GAIN_TLV, \
-         .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
-         .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
-
-#define SST_GAIN_KCONTROL_INT(xname, xhandler_get, xhandler_put, \
-                             xmod, xpipe, xinstance, xtask, xtype, xgain_val, \
-                             xmin, xmax, xpname) \
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = sst_gain_ctl_info, \
-       .get = xhandler_get, .put = xhandler_put, \
-       .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
-       { .stereo = false, .max = xmax, .min = xmin, .type = xtype, \
-         .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
-         .instance_id = xinstance, .gain_val = xgain_val, .pname =  xpname}
-
-#define SST_GAIN_KCONTROL_BOOL(xname, xhandler_get, xhandler_put,\
-                              xmod, xpipe, xinstance, xtask, xgain_val, xpname) \
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_bool_ext, \
-       .get = xhandler_get, .put = xhandler_put, \
-       .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
-       { .stereo = false, .type = SST_GAIN_MUTE, \
-         .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
-         .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
-#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
-       xpname " " xmname " " #xinstance " " xtype
-
-#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
-       xpname " " xmname " " #xinstance " " xtype " " xsubmodule
-
-/*
- * 3 Controls for each Gain module
- * e.g.        - pcm0_in Gain 0 Volume
- *     - pcm0_in Gain 0 Ramp Delay
- *     - pcm0_in Gain 0 Switch
- */
-#define SST_GAIN_KCONTROLS(xpname, xmname, xmin_gain, xmax_gain, xmin_tc, xmax_tc, \
-                          xhandler_get, xhandler_put, \
-                          xmod, xpipe, xinstance, xtask, tlv_array, xgain_val) \
-       { SST_GAIN_KCONTROL_INT(SST_CONTROL_NAME(xpname, xmname, xinstance, "Ramp Delay"), \
-               xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, SST_GAIN_RAMP_DURATION, \
-               xgain_val, xmin_tc, xmax_tc, xpname) }, \
-       { SST_GAIN_KCONTROL_BOOL(SST_CONTROL_NAME(xpname, xmname, xinstance, "Switch"), \
-               xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, \
-               xgain_val, xpname) } ,\
-       { SST_GAIN_KCONTROL_TLV(SST_CONTROL_NAME(xpname, xmname, xinstance, "Volume"), \
-               xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, tlv_array, \
-               xgain_val, xmin_gain, xmax_gain, xpname) }
-
-#define SST_GAIN_TC_MIN                5
-#define SST_GAIN_TC_MAX                5000
-#define SST_GAIN_MIN_VALUE     -1440 /* in 0.1 DB units */
-#define SST_GAIN_MAX_VALUE     360
-
-enum sst_algo_kcontrol_type {
-       SST_ALGO_PARAMS,
-       SST_ALGO_BYPASS,
-};
-
-struct sst_algo_control {
-       enum sst_algo_kcontrol_type type;
-       int max;
-       u16 module_id;
-       u16 pipe_id;
-       u16 task_id;
-       u16 cmd_id;
-       bool bypass;
-       unsigned char *params;
-       struct snd_soc_dapm_widget *w;
-};
-
-/* size of the control = size of params + size of length field */
-#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd)                    \
-       (struct sst_algo_control){                                                      \
-               .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod,                  \
-               .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd,                     \
-       }
-
-#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe,                                  \
-                         xtask, xcmd, xtype, xinfo, xget, xput)                        \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,                                            \
-       .name =  xname,                                                                 \
-       .info = xinfo, .get = xget, .put = xput,                                        \
-       .private_value = (unsigned long)&                                               \
-                       SST_ALGO_CTL_VALUE(xcount, xtype, xpipe,                        \
-                                          xmod, xtask, xcmd),                          \
-}
-
-#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod,                          \
-                               xpipe, xinstance, xtask, xcmd)                          \
-       SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"),        \
-                         xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,            \
-                         sst_algo_bytes_ctl_info,                                      \
-                         sst_algo_control_get, sst_algo_control_set)
-
-#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask)          \
-       SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"),        \
-                         0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS,                    \
-                         snd_soc_info_bool_ext,                                        \
-                         sst_algo_control_get, sst_algo_control_set)
-
-#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe,                    \
-                               xinstance, xtask, xcmd)                                 \
-       SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask),          \
-       SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd)
-
-#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod,           \
-                                     xpipe, xinstance, xtask, xcmd)                    \
-       SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params",   \
-                                                xsubmod),                              \
-                         xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,            \
-                         sst_algo_bytes_ctl_info,                                      \
-                         sst_algo_control_get, sst_algo_control_set)
-
-
-struct sst_enum {
-       bool tx;
-       unsigned short reg;
-       unsigned int max;
-       const char * const *texts;
-       struct snd_soc_dapm_widget *w;
-};
-
-/* only 4 slots/channels supported atm */
-#define SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts) \
-       (struct sst_enum){ .reg = s_ch_no, .tx = is_tx, .max = 4+1, .texts = xtexts, }
-
-#define SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name) \
-       xpname " " xmname " " s_ch_name
-
-#define SST_SSP_SLOT_CTL(xpname, xmname, s_ch_name, s_ch_no, is_tx, xtexts, xget, xput) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-       .name = SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name), \
-       .info = sst_slot_enum_info, \
-       .get = xget, .put = xput, \
-       .private_value = (unsigned long)&SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts), \
-}
-
-#define SST_MUX_CTL_NAME(xpname, xinstance) \
-       xpname " " #xinstance
-
-#define SST_SSP_MUX_ENUM(xreg, xshift, xtexts) \
-       (struct soc_enum) SOC_ENUM_DOUBLE(xreg, xshift, xshift, ARRAY_SIZE(xtexts), xtexts)
-
-#define SST_SSP_MUX_CTL(xpname, xinstance, xreg, xshift, xtexts) \
-       SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \
-                         SST_SSP_MUX_ENUM(xreg, xshift, xtexts))
-
-#endif
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c
deleted file mode 100644 (file)
index 5a9e567..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Intel Baytrail SST DSP driver
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/firmware.h>
-
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-#include "sst-baytrail-ipc.h"
-
-#define SST_BYT_FW_SIGNATURE_SIZE      4
-#define SST_BYT_FW_SIGN                        "$SST"
-
-#define SST_BYT_IRAM_OFFSET    0xC0000
-#define SST_BYT_DRAM_OFFSET    0x100000
-#define SST_BYT_SHIM_OFFSET    0x140000
-
-enum sst_ram_type {
-       SST_BYT_IRAM    = 1,
-       SST_BYT_DRAM    = 2,
-       SST_BYT_CACHE   = 3,
-};
-
-struct dma_block_info {
-       enum sst_ram_type       type;   /* IRAM/DRAM */
-       u32                     size;   /* Bytes */
-       u32                     ram_offset; /* Offset in I/DRAM */
-       u32                     rsvd;   /* Reserved field */
-};
-
-struct fw_header {
-       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
-       u32 file_size; /* size of fw minus this header */
-       u32 modules; /*  # of modules */
-       u32 file_format; /* version of header format */
-       u32 reserved[4];
-};
-
-struct sst_byt_fw_module_header {
-       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
-       u32 mod_size; /* size of module */
-       u32 blocks; /* # of blocks */
-       u32 type; /* codec type, pp lib */
-       u32 entry_point;
-};
-
-static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
-                               struct sst_byt_fw_module_header *module)
-{
-       struct dma_block_info *block;
-       struct sst_module *mod;
-       struct sst_module_template template;
-       int count;
-
-       memset(&template, 0, sizeof(template));
-       template.id = module->type;
-       template.entry = module->entry_point;
-
-       mod = sst_module_new(fw, &template, NULL);
-       if (mod == NULL)
-               return -ENOMEM;
-
-       block = (void *)module + sizeof(*module);
-
-       for (count = 0; count < module->blocks; count++) {
-
-               if (block->size <= 0) {
-                       dev_err(dsp->dev, "block %d size invalid\n", count);
-                       return -EINVAL;
-               }
-
-               switch (block->type) {
-               case SST_BYT_IRAM:
-                       mod->offset = block->ram_offset +
-                                           dsp->addr.iram_offset;
-                       mod->type = SST_MEM_IRAM;
-                       break;
-               case SST_BYT_DRAM:
-                       mod->offset = block->ram_offset +
-                                           dsp->addr.dram_offset;
-                       mod->type = SST_MEM_DRAM;
-                       break;
-               case SST_BYT_CACHE:
-                       mod->offset = block->ram_offset +
-                                           (dsp->addr.fw_ext - dsp->addr.lpe);
-                       mod->type = SST_MEM_CACHE;
-                       break;
-               default:
-                       dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
-                               block->type, count);
-                       return -EINVAL;
-               }
-
-               mod->size = block->size;
-               mod->data = (void *)block + sizeof(*block);
-
-               sst_module_alloc_blocks(mod);
-
-               block = (void *)block + sizeof(*block) + block->size;
-       }
-       return 0;
-}
-
-static int sst_byt_parse_fw_image(struct sst_fw *sst_fw)
-{
-       struct fw_header *header;
-       struct sst_byt_fw_module_header *module;
-       struct sst_dsp *dsp = sst_fw->dsp;
-       int ret, count;
-
-       /* Read the header information from the data pointer */
-       header = (struct fw_header *)sst_fw->dma_buf;
-
-       /* verify FW */
-       if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) ||
-           (sst_fw->size != header->file_size + sizeof(*header))) {
-               /* Invalid FW signature */
-               dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n");
-               return -EINVAL;
-       }
-
-       dev_dbg(dsp->dev,
-               "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
-               header->signature, header->file_size, header->modules,
-               header->file_format, sizeof(*header));
-
-       module = (void *)sst_fw->dma_buf + sizeof(*header);
-       for (count = 0; count < header->modules; count++) {
-               /* module */
-               ret = sst_byt_parse_module(dsp, sst_fw, module);
-               if (ret < 0) {
-                       dev_err(dsp->dev, "invalid module %d\n", count);
-                       return ret;
-               }
-               module = (void *)module + sizeof(*module) + module->mod_size;
-       }
-
-       return 0;
-}
-
-static void sst_byt_dump_shim(struct sst_dsp *sst)
-{
-       int i;
-       u64 reg;
-
-       for (i = 0; i <= 0xF0; i += 8) {
-               reg = sst_dsp_shim_read64_unlocked(sst, i);
-               if (reg)
-                       dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n",
-                               i, reg);
-       }
-
-       for (i = 0x00; i <= 0xff; i += 4) {
-               reg = readl(sst->addr.pci_cfg + i);
-               if (reg)
-                       dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n",
-                               i, (u32)reg);
-       }
-}
-
-static irqreturn_t sst_byt_irq(int irq, void *context)
-{
-       struct sst_dsp *sst = (struct sst_dsp *) context;
-       u64 isrx;
-       irqreturn_t ret = IRQ_NONE;
-
-       spin_lock(&sst->spinlock);
-
-       isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
-       if (isrx & SST_ISRX_DONE) {
-               /* ADSP has processed the message request from IA */
-               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX,
-                                                   SST_BYT_IPCX_DONE, 0);
-               ret = IRQ_WAKE_THREAD;
-       }
-       if (isrx & SST_BYT_ISRX_REQUEST) {
-               /* mask message request from ADSP and do processing later */
-               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
-                                                   SST_BYT_IMRX_REQUEST,
-                                                   SST_BYT_IMRX_REQUEST);
-               ret = IRQ_WAKE_THREAD;
-       }
-
-       spin_unlock(&sst->spinlock);
-
-       return ret;
-}
-
-static void sst_byt_boot(struct sst_dsp *sst)
-{
-       int tries = 10;
-
-       /*
-        * save the physical address of extended firmware block in the first
-        * 4 bytes of the mailbox
-        */
-       memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
-              &sst->pdata->fw_base, sizeof(u32));
-
-       /* release stall and wait to unstall */
-       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
-       while (tries--) {
-               if (!(sst_dsp_shim_read64(sst, SST_CSR) &
-                     SST_BYT_CSR_PWAITMODE))
-                       break;
-               msleep(100);
-       }
-       if (tries < 0) {
-               dev_err(sst->dev, "unable to start DSP\n");
-               sst_byt_dump_shim(sst);
-       }
-}
-
-static void sst_byt_reset(struct sst_dsp *sst)
-{
-       /* put DSP into reset, set reset vector and stall */
-       sst_dsp_shim_update_bits64(sst, SST_CSR,
-               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL,
-               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL);
-
-       udelay(10);
-
-       /* take DSP out of reset and keep stalled for FW loading */
-       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0);
-}
-
-struct sst_adsp_memregion {
-       u32 start;
-       u32 end;
-       int blocks;
-       enum sst_mem_type type;
-};
-
-/* BYT test stuff */
-static const struct sst_adsp_memregion byt_region[] = {
-       {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */
-       {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
-};
-
-static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
-{
-       sst->addr.lpe_base = pdata->lpe_base;
-       sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
-       if (!sst->addr.lpe)
-               return -ENODEV;
-
-       /* ADSP PCI MMIO config space */
-       sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
-       if (!sst->addr.pci_cfg) {
-               iounmap(sst->addr.lpe);
-               return -ENODEV;
-       }
-
-       /* SST Extended FW allocation */
-       sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size);
-       if (!sst->addr.fw_ext) {
-               iounmap(sst->addr.pci_cfg);
-               iounmap(sst->addr.lpe);
-               return -ENODEV;
-       }
-
-       /* SST Shim */
-       sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
-
-       sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204,
-                            SST_BYT_IPC_MAX_PAYLOAD_SIZE,
-                            SST_BYT_MAILBOX_OFFSET,
-                            SST_BYT_IPC_MAX_PAYLOAD_SIZE);
-
-       sst->irq = pdata->irq;
-
-       return 0;
-}
-
-static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
-{
-       const struct sst_adsp_memregion *region;
-       struct device *dev;
-       int ret = -ENODEV, i, j, region_count;
-       u32 offset, size;
-
-       dev = sst->dev;
-
-       switch (sst->id) {
-       case SST_DEV_ID_BYT:
-               region = byt_region;
-               region_count = ARRAY_SIZE(byt_region);
-               sst->addr.iram_offset = SST_BYT_IRAM_OFFSET;
-               sst->addr.dram_offset = SST_BYT_DRAM_OFFSET;
-               sst->addr.shim_offset = SST_BYT_SHIM_OFFSET;
-               break;
-       default:
-               dev_err(dev, "failed to get mem resources\n");
-               return ret;
-       }
-
-       ret = sst_byt_resource_map(sst, pdata);
-       if (ret < 0) {
-               dev_err(dev, "failed to map resources\n");
-               return ret;
-       }
-
-       ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       /* enable Interrupt from both sides */
-       sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0);
-       sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0);
-
-       /* register DSP memory blocks - ideally we should get this from ACPI */
-       for (i = 0; i < region_count; i++) {
-               offset = region[i].start;
-               size = (region[i].end - region[i].start) / region[i].blocks;
-
-               /* register individual memory blocks */
-               for (j = 0; j < region[i].blocks; j++) {
-                       sst_mem_block_register(sst, offset, size,
-                                              region[i].type, NULL, j, sst);
-                       offset += size;
-               }
-       }
-
-       return 0;
-}
-
-static void sst_byt_free(struct sst_dsp *sst)
-{
-       sst_mem_block_unregister_all(sst);
-       iounmap(sst->addr.lpe);
-       iounmap(sst->addr.pci_cfg);
-       iounmap(sst->addr.fw_ext);
-}
-
-struct sst_ops sst_byt_ops = {
-       .reset = sst_byt_reset,
-       .boot = sst_byt_boot,
-       .write = sst_shim32_write,
-       .read = sst_shim32_read,
-       .write64 = sst_shim32_write64,
-       .read64 = sst_shim32_read64,
-       .ram_read = sst_memcpy_fromio_32,
-       .ram_write = sst_memcpy_toio_32,
-       .irq_handler = sst_byt_irq,
-       .init = sst_byt_init,
-       .free = sst_byt_free,
-       .parse_fw = sst_byt_parse_fw_image,
-};
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c
deleted file mode 100644 (file)
index b4ad98c..0000000
+++ /dev/null
@@ -1,983 +0,0 @@
-/*
- * Intel Baytrail SST IPC Support
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/kthread.h>
-#include <linux/firmware.h>
-#include <linux/io.h>
-#include <asm/div64.h>
-
-#include "sst-baytrail-ipc.h"
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-
-/* IPC message timeout */
-#define IPC_TIMEOUT_MSECS      300
-#define IPC_BOOT_MSECS         200
-
-#define IPC_EMPTY_LIST_SIZE    8
-
-/* IPC header bits */
-#define IPC_HEADER_MSG_ID_MASK 0xff
-#define IPC_HEADER_MSG_ID(x)   ((x) & IPC_HEADER_MSG_ID_MASK)
-#define IPC_HEADER_STR_ID_SHIFT        8
-#define IPC_HEADER_STR_ID_MASK 0x1f
-#define IPC_HEADER_STR_ID(x)   (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT)
-#define IPC_HEADER_LARGE_SHIFT 13
-#define IPC_HEADER_LARGE(x)    (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT)
-#define IPC_HEADER_DATA_SHIFT  16
-#define IPC_HEADER_DATA_MASK   0x3fff
-#define IPC_HEADER_DATA(x)     (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT)
-
-/* mask for differentiating between notification and reply message */
-#define IPC_NOTIFICATION       (0x1 << 7)
-
-/* I2L Stream config/control msgs */
-#define IPC_IA_ALLOC_STREAM    0x20
-#define IPC_IA_FREE_STREAM     0x21
-#define IPC_IA_PAUSE_STREAM    0x24
-#define IPC_IA_RESUME_STREAM   0x25
-#define IPC_IA_DROP_STREAM     0x26
-#define IPC_IA_START_STREAM    0x30
-
-/* notification messages */
-#define IPC_IA_FW_INIT_CMPLT   0x81
-#define IPC_SST_PERIOD_ELAPSED 0x97
-
-/* IPC messages between host and ADSP */
-struct sst_byt_address_info {
-       u32 addr;
-       u32 size;
-} __packed;
-
-struct sst_byt_str_type {
-       u8 codec_type;
-       u8 str_type;
-       u8 operation;
-       u8 protected_str;
-       u8 time_slots;
-       u8 reserved;
-       u16 result;
-} __packed;
-
-struct sst_byt_pcm_params {
-       u8 num_chan;
-       u8 pcm_wd_sz;
-       u8 use_offload_path;
-       u8 reserved;
-       u32 sfreq;
-       u8 channel_map[8];
-} __packed;
-
-struct sst_byt_frames_info {
-       u16 num_entries;
-       u16 rsrvd;
-       u32 frag_size;
-       struct sst_byt_address_info ring_buf_info[8];
-} __packed;
-
-struct sst_byt_alloc_params {
-       struct sst_byt_str_type str_type;
-       struct sst_byt_pcm_params pcm_params;
-       struct sst_byt_frames_info frame_info;
-} __packed;
-
-struct sst_byt_alloc_response {
-       struct sst_byt_str_type str_type;
-       u8 reserved[88];
-} __packed;
-
-struct sst_byt_start_stream_params {
-       u32 byte_offset;
-} __packed;
-
-struct sst_byt_tstamp {
-       u64 ring_buffer_counter;
-       u64 hardware_counter;
-       u64 frames_decoded;
-       u64 bytes_decoded;
-       u64 bytes_copied;
-       u32 sampling_frequency;
-       u32 channel_peak[8];
-} __packed;
-
-struct sst_byt_fw_version {
-       u8 build;
-       u8 minor;
-       u8 major;
-       u8 type;
-} __packed;
-
-struct sst_byt_fw_build_info {
-       u8 date[16];
-       u8 time[16];
-} __packed;
-
-struct sst_byt_fw_init {
-       struct sst_byt_fw_version fw_version;
-       struct sst_byt_fw_build_info build_info;
-       u16 result;
-       u8 module_id;
-       u8 debug_info;
-} __packed;
-
-/* driver internal IPC message structure */
-struct ipc_message {
-       struct list_head list;
-       u64 header;
-
-       /* direction wrt host CPU */
-       char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
-       size_t tx_size;
-       char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
-       size_t rx_size;
-
-       wait_queue_head_t waitq;
-       bool complete;
-       bool wait;
-       int errno;
-};
-
-struct sst_byt_stream;
-struct sst_byt;
-
-/* stream infomation */
-struct sst_byt_stream {
-       struct list_head node;
-
-       /* configuration */
-       struct sst_byt_alloc_params request;
-       struct sst_byt_alloc_response reply;
-
-       /* runtime info */
-       struct sst_byt *byt;
-       int str_id;
-       bool commited;
-       bool running;
-
-       /* driver callback */
-       u32 (*notify_position)(struct sst_byt_stream *stream, void *data);
-       void *pdata;
-};
-
-/* SST Baytrail IPC data */
-struct sst_byt {
-       struct device *dev;
-       struct sst_dsp *dsp;
-
-       /* stream */
-       struct list_head stream_list;
-
-       /* boot */
-       wait_queue_head_t boot_wait;
-       bool boot_complete;
-       struct sst_fw *fw;
-
-       /* IPC messaging */
-       struct list_head tx_list;
-       struct list_head rx_list;
-       struct list_head empty_list;
-       wait_queue_head_t wait_txq;
-       struct task_struct *tx_thread;
-       struct kthread_worker kworker;
-       struct kthread_work kwork;
-       struct ipc_message *msg;
-};
-
-static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id)
-{
-       u64 header;
-
-       header = IPC_HEADER_MSG_ID(msg_id) |
-                IPC_HEADER_STR_ID(str_id) |
-                IPC_HEADER_LARGE(large) |
-                IPC_HEADER_DATA(data) |
-                SST_BYT_IPCX_BUSY;
-
-       return header;
-}
-
-static inline u16 sst_byt_header_msg_id(u64 header)
-{
-       return header & IPC_HEADER_MSG_ID_MASK;
-}
-
-static inline u8 sst_byt_header_str_id(u64 header)
-{
-       return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK;
-}
-
-static inline u16 sst_byt_header_data(u64 header)
-{
-       return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK;
-}
-
-static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt,
-                                                int stream_id)
-{
-       struct sst_byt_stream *stream;
-
-       list_for_each_entry(stream, &byt->stream_list, node) {
-               if (stream->str_id == stream_id)
-                       return stream;
-       }
-
-       return NULL;
-}
-
-static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text)
-{
-       struct sst_dsp *sst = byt->dsp;
-       u64 isr, ipcd, imrx, ipcx;
-
-       ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX);
-       isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
-       ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
-       imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX);
-
-       dev_err(byt->dev,
-               "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n",
-               text, ipcx, isr, ipcd, imrx);
-}
-
-/* locks held by caller */
-static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt)
-{
-       struct ipc_message *msg = NULL;
-
-       if (!list_empty(&byt->empty_list)) {
-               msg = list_first_entry(&byt->empty_list,
-                                      struct ipc_message, list);
-               list_del(&msg->list);
-       }
-
-       return msg;
-}
-
-static void sst_byt_ipc_tx_msgs(struct kthread_work *work)
-{
-       struct sst_byt *byt =
-               container_of(work, struct sst_byt, kwork);
-       struct ipc_message *msg;
-       u64 ipcx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&byt->dsp->spinlock, flags);
-       if (list_empty(&byt->tx_list)) {
-               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-               return;
-       }
-
-       /* if the DSP is busy we will TX messages after IRQ */
-       ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX);
-       if (ipcx & SST_BYT_IPCX_BUSY) {
-               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-               return;
-       }
-
-       msg = list_first_entry(&byt->tx_list, struct ipc_message, list);
-
-       list_move(&msg->list, &byt->rx_list);
-
-       /* send the message */
-       if (msg->header & IPC_HEADER_LARGE(true))
-               sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size);
-       sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header);
-
-       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-}
-
-static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
-                                                struct ipc_message *msg)
-{
-       msg->complete = true;
-
-       if (!msg->wait)
-               list_add_tail(&msg->list, &byt->empty_list);
-       else
-               wake_up(&msg->waitq);
-}
-
-static void sst_byt_drop_all(struct sst_byt *byt)
-{
-       struct ipc_message *msg, *tmp;
-       unsigned long flags;
-
-       /* drop all TX and Rx messages before we stall + reset DSP */
-       spin_lock_irqsave(&byt->dsp->spinlock, flags);
-       list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) {
-               list_move(&msg->list, &byt->empty_list);
-       }
-
-       list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) {
-               list_move(&msg->list, &byt->empty_list);
-       }
-
-       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-}
-
-static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
-                               void *rx_data)
-{
-       unsigned long flags;
-       int ret;
-
-       /* wait for DSP completion */
-       ret = wait_event_timeout(msg->waitq, msg->complete,
-                                msecs_to_jiffies(IPC_TIMEOUT_MSECS));
-
-       spin_lock_irqsave(&byt->dsp->spinlock, flags);
-       if (ret == 0) {
-               list_del(&msg->list);
-               sst_byt_ipc_shim_dbg(byt, "message timeout");
-
-               ret = -ETIMEDOUT;
-       } else {
-
-               /* copy the data returned from DSP */
-               if (msg->rx_size)
-                       memcpy(rx_data, msg->rx_data, msg->rx_size);
-               ret = msg->errno;
-       }
-
-       list_add_tail(&msg->list, &byt->empty_list);
-       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-       return ret;
-}
-
-static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header,
-                                 void *tx_data, size_t tx_bytes,
-                                 void *rx_data, size_t rx_bytes, int wait)
-{
-       unsigned long flags;
-       struct ipc_message *msg;
-
-       spin_lock_irqsave(&byt->dsp->spinlock, flags);
-
-       msg = sst_byt_msg_get_empty(byt);
-       if (msg == NULL) {
-               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-               return -EBUSY;
-       }
-
-       msg->header = header;
-       msg->tx_size = tx_bytes;
-       msg->rx_size = rx_bytes;
-       msg->wait = wait;
-       msg->errno = 0;
-       msg->complete = false;
-
-       if (tx_bytes) {
-               /* msg content = lower 32-bit of the header + data */
-               *(u32 *)msg->tx_data = (u32)(header & (u32)-1);
-               memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes);
-               msg->tx_size += sizeof(u32);
-       }
-
-       list_add_tail(&msg->list, &byt->tx_list);
-       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
-
-       queue_kthread_work(&byt->kworker, &byt->kwork);
-
-       if (wait)
-               return sst_byt_tx_wait_done(byt, msg, rx_data);
-       else
-               return 0;
-}
-
-static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header,
-                                         void *tx_data, size_t tx_bytes,
-                                         void *rx_data, size_t rx_bytes)
-{
-       return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
-                                     rx_data, rx_bytes, 1);
-}
-
-static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header,
-                                               void *tx_data, size_t tx_bytes)
-{
-       return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
-                                     NULL, 0, 0);
-}
-
-static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt,
-                                                 u64 header)
-{
-       struct ipc_message *msg = NULL, *_msg;
-       u64 mask;
-
-       /* match reply to message sent based on msg and stream IDs */
-       mask = IPC_HEADER_MSG_ID_MASK |
-              IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT;
-       header &= mask;
-
-       if (list_empty(&byt->rx_list)) {
-               dev_err(byt->dev,
-                       "ipc: rx list is empty but received 0x%llx\n", header);
-               goto out;
-       }
-
-       list_for_each_entry(_msg, &byt->rx_list, list) {
-               if ((_msg->header & mask) == header) {
-                       msg = _msg;
-                       break;
-               }
-       }
-
-out:
-       return msg;
-}
-
-static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg)
-{
-       struct sst_byt_stream *stream;
-       u64 header = msg->header;
-       u8 stream_id = sst_byt_header_str_id(header);
-       u8 stream_msg = sst_byt_header_msg_id(header);
-
-       stream = sst_byt_get_stream(byt, stream_id);
-       if (stream == NULL)
-               return;
-
-       switch (stream_msg) {
-       case IPC_IA_DROP_STREAM:
-       case IPC_IA_PAUSE_STREAM:
-       case IPC_IA_FREE_STREAM:
-               stream->running = false;
-               break;
-       case IPC_IA_START_STREAM:
-       case IPC_IA_RESUME_STREAM:
-               stream->running = true;
-               break;
-       }
-}
-
-static int sst_byt_process_reply(struct sst_byt *byt, u64 header)
-{
-       struct ipc_message *msg;
-
-       msg = sst_byt_reply_find_msg(byt, header);
-       if (msg == NULL)
-               return 1;
-
-       if (header & IPC_HEADER_LARGE(true)) {
-               msg->rx_size = sst_byt_header_data(header);
-               sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size);
-       }
-
-       /* update any stream states */
-       sst_byt_stream_update(byt, msg);
-
-       list_del(&msg->list);
-       /* wake up */
-       sst_byt_tx_msg_reply_complete(byt, msg);
-
-       return 1;
-}
-
-static void sst_byt_fw_ready(struct sst_byt *byt, u64 header)
-{
-       dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header);
-
-       byt->boot_complete = true;
-       wake_up(&byt->boot_wait);
-}
-
-static int sst_byt_process_notification(struct sst_byt *byt,
-                                       unsigned long *flags)
-{
-       struct sst_dsp *sst = byt->dsp;
-       struct sst_byt_stream *stream;
-       u64 header;
-       u8 msg_id, stream_id;
-       int handled = 1;
-
-       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
-       msg_id = sst_byt_header_msg_id(header);
-
-       switch (msg_id) {
-       case IPC_SST_PERIOD_ELAPSED:
-               stream_id = sst_byt_header_str_id(header);
-               stream = sst_byt_get_stream(byt, stream_id);
-               if (stream && stream->running && stream->notify_position) {
-                       spin_unlock_irqrestore(&sst->spinlock, *flags);
-                       stream->notify_position(stream, stream->pdata);
-                       spin_lock_irqsave(&sst->spinlock, *flags);
-               }
-               break;
-       case IPC_IA_FW_INIT_CMPLT:
-               sst_byt_fw_ready(byt, header);
-               break;
-       }
-
-       return handled;
-}
-
-static irqreturn_t sst_byt_irq_thread(int irq, void *context)
-{
-       struct sst_dsp *sst = (struct sst_dsp *) context;
-       struct sst_byt *byt = sst_dsp_get_thread_context(sst);
-       u64 header;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-
-       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
-       if (header & SST_BYT_IPCD_BUSY) {
-               if (header & IPC_NOTIFICATION) {
-                       /* message from ADSP */
-                       sst_byt_process_notification(byt, &flags);
-               } else {
-                       /* reply from ADSP */
-                       sst_byt_process_reply(byt, header);
-               }
-               /*
-                * clear IPCD BUSY bit and set DONE bit. Tell DSP we have
-                * processed the message and can accept new. Clear data part
-                * of the header
-                */
-               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD,
-                       SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
-                       IPC_HEADER_DATA(IPC_HEADER_DATA_MASK),
-                       SST_BYT_IPCD_DONE);
-               /* unmask message request interrupts */
-               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
-                       SST_BYT_IMRX_REQUEST, 0);
-       }
-
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       /* continue to send any remaining messages... */
-       queue_kthread_work(&byt->kworker, &byt->kwork);
-
-       return IRQ_HANDLED;
-}
-
-/* stream API */
-struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
-       u32 (*notify_position)(struct sst_byt_stream *stream, void *data),
-       void *data)
-{
-       struct sst_byt_stream *stream;
-       struct sst_dsp *sst = byt->dsp;
-       unsigned long flags;
-
-       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-       if (stream == NULL)
-               return NULL;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       list_add(&stream->node, &byt->stream_list);
-       stream->notify_position = notify_position;
-       stream->pdata = data;
-       stream->byt = byt;
-       stream->str_id = id;
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       return stream;
-}
-
-int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
-                           int bits)
-{
-       stream->request.pcm_params.pcm_wd_sz = bits;
-       return 0;
-}
-
-int sst_byt_stream_set_channels(struct sst_byt *byt,
-                               struct sst_byt_stream *stream, u8 channels)
-{
-       stream->request.pcm_params.num_chan = channels;
-       return 0;
-}
-
-int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
-                           unsigned int rate)
-{
-       stream->request.pcm_params.sfreq = rate;
-       return 0;
-}
-
-/* stream sonfiguration */
-int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
-                       int codec_type, int stream_type, int operation)
-{
-       stream->request.str_type.codec_type = codec_type;
-       stream->request.str_type.str_type = stream_type;
-       stream->request.str_type.operation = operation;
-       stream->request.str_type.time_slots = 0xc;
-
-       return 0;
-}
-
-int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
-                         uint32_t buffer_addr, uint32_t buffer_size)
-{
-       stream->request.frame_info.num_entries = 1;
-       stream->request.frame_info.ring_buf_info[0].addr = buffer_addr;
-       stream->request.frame_info.ring_buf_info[0].size = buffer_size;
-       /* calculate bytes per 4 ms fragment */
-       stream->request.frame_info.frag_size =
-               stream->request.pcm_params.sfreq *
-               stream->request.pcm_params.num_chan *
-               stream->request.pcm_params.pcm_wd_sz / 8 *
-               4 / 1000;
-       return 0;
-}
-
-int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       struct sst_byt_alloc_params *str_req = &stream->request;
-       struct sst_byt_alloc_response *reply = &stream->reply;
-       u64 header;
-       int ret;
-
-       header = sst_byt_header(IPC_IA_ALLOC_STREAM,
-                               sizeof(*str_req) + sizeof(u32),
-                               true, stream->str_id);
-       ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req),
-                                     reply, sizeof(*reply));
-       if (ret < 0) {
-               dev_err(byt->dev, "ipc: error stream commit failed\n");
-               return ret;
-       }
-
-       stream->commited = true;
-
-       return 0;
-}
-
-int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       u64 header;
-       int ret = 0;
-       struct sst_dsp *sst = byt->dsp;
-       unsigned long flags;
-
-       if (!stream->commited)
-               goto out;
-
-       header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id);
-       ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
-       if (ret < 0) {
-               dev_err(byt->dev, "ipc: free stream %d failed\n",
-                       stream->str_id);
-               return -EAGAIN;
-       }
-
-       stream->commited = false;
-out:
-       spin_lock_irqsave(&sst->spinlock, flags);
-       list_del(&stream->node);
-       kfree(stream);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       return ret;
-}
-
-static int sst_byt_stream_operations(struct sst_byt *byt, int type,
-                                    int stream_id, int wait)
-{
-       u64 header;
-
-       header = sst_byt_header(type, 0, false, stream_id);
-       if (wait)
-               return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
-       else
-               return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0);
-}
-
-/* stream ALSA trigger operations */
-int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
-                        u32 start_offset)
-{
-       struct sst_byt_start_stream_params start_stream;
-       void *tx_msg;
-       size_t size;
-       u64 header;
-       int ret;
-
-       start_stream.byte_offset = start_offset;
-       header = sst_byt_header(IPC_IA_START_STREAM,
-                               sizeof(start_stream) + sizeof(u32),
-                               true, stream->str_id);
-       tx_msg = &start_stream;
-       size = sizeof(start_stream);
-
-       ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
-       if (ret < 0)
-               dev_err(byt->dev, "ipc: error failed to start stream %d\n",
-                       stream->str_id);
-
-       return ret;
-}
-
-int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       int ret;
-
-       /* don't stop streams that are not commited */
-       if (!stream->commited)
-               return 0;
-
-       ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM,
-                                       stream->str_id, 0);
-       if (ret < 0)
-               dev_err(byt->dev, "ipc: error failed to stop stream %d\n",
-                       stream->str_id);
-       return ret;
-}
-
-int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       int ret;
-
-       ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM,
-                                       stream->str_id, 0);
-       if (ret < 0)
-               dev_err(byt->dev, "ipc: error failed to pause stream %d\n",
-                       stream->str_id);
-
-       return ret;
-}
-
-int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream)
-{
-       int ret;
-
-       ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM,
-                                       stream->str_id, 0);
-       if (ret < 0)
-               dev_err(byt->dev, "ipc: error failed to resume stream %d\n",
-                       stream->str_id);
-
-       return ret;
-}
-
-int sst_byt_get_dsp_position(struct sst_byt *byt,
-                            struct sst_byt_stream *stream, int buffer_size)
-{
-       struct sst_dsp *sst = byt->dsp;
-       struct sst_byt_tstamp fw_tstamp;
-       u8 str_id = stream->str_id;
-       u32 tstamp_offset;
-
-       tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp);
-       memcpy_fromio(&fw_tstamp,
-                     sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp));
-
-       return do_div(fw_tstamp.ring_buffer_counter, buffer_size);
-}
-
-static int msg_empty_list_init(struct sst_byt *byt)
-{
-       struct ipc_message *msg;
-       int i;
-
-       byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
-       if (byt->msg == NULL)
-               return -ENOMEM;
-
-       for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
-               init_waitqueue_head(&byt->msg[i].waitq);
-               list_add(&byt->msg[i].list, &byt->empty_list);
-       }
-
-       return 0;
-}
-
-struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt)
-{
-       return byt->dsp;
-}
-
-static struct sst_dsp_device byt_dev = {
-       .thread = sst_byt_irq_thread,
-       .ops = &sst_byt_ops,
-};
-
-int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-
-       dev_dbg(byt->dev, "dsp reset\n");
-       sst_dsp_reset(byt->dsp);
-       sst_byt_drop_all(byt);
-       dev_dbg(byt->dev, "dsp in reset\n");
-
-       dev_dbg(byt->dev, "free all blocks and unload fw\n");
-       sst_fw_unload(byt->fw);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
-
-int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-       int ret;
-
-       dev_dbg(byt->dev, "reload dsp fw\n");
-
-       sst_dsp_reset(byt->dsp);
-
-       ret = sst_fw_reload(byt->fw);
-       if (ret <  0) {
-               dev_err(dev, "error: failed to reload firmware\n");
-               return ret;
-       }
-
-       /* wait for DSP boot completion */
-       byt->boot_complete = false;
-       sst_dsp_boot(byt->dsp);
-       dev_dbg(byt->dev, "dsp booting...\n");
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
-
-int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-       int err;
-
-       dev_dbg(byt->dev, "wait for dsp reboot\n");
-
-       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
-                                msecs_to_jiffies(IPC_BOOT_MSECS));
-       if (err == 0) {
-               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
-               return -EIO;
-       }
-
-       dev_dbg(byt->dev, "dsp rebooted\n");
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
-
-int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt;
-       struct sst_fw *byt_sst_fw;
-       struct sst_byt_fw_init init;
-       int err;
-
-       dev_dbg(dev, "initialising Byt DSP IPC\n");
-
-       byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL);
-       if (byt == NULL)
-               return -ENOMEM;
-
-       byt->dev = dev;
-       INIT_LIST_HEAD(&byt->stream_list);
-       INIT_LIST_HEAD(&byt->tx_list);
-       INIT_LIST_HEAD(&byt->rx_list);
-       INIT_LIST_HEAD(&byt->empty_list);
-       init_waitqueue_head(&byt->boot_wait);
-       init_waitqueue_head(&byt->wait_txq);
-
-       err = msg_empty_list_init(byt);
-       if (err < 0)
-               return -ENOMEM;
-
-       /* start the IPC message thread */
-       init_kthread_worker(&byt->kworker);
-       byt->tx_thread = kthread_run(kthread_worker_fn,
-                                    &byt->kworker, "%s",
-                                    dev_name(byt->dev));
-       if (IS_ERR(byt->tx_thread)) {
-               err = PTR_ERR(byt->tx_thread);
-               dev_err(byt->dev, "error failed to create message TX task\n");
-               goto err_free_msg;
-       }
-       init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs);
-
-       byt_dev.thread_context = byt;
-
-       /* init SST shim */
-       byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
-       if (byt->dsp == NULL) {
-               err = -ENODEV;
-               goto dsp_err;
-       }
-
-       /* keep the DSP in reset state for base FW loading */
-       sst_dsp_reset(byt->dsp);
-
-       byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt);
-       if (byt_sst_fw  == NULL) {
-               err = -ENODEV;
-               dev_err(dev, "error: failed to load firmware\n");
-               goto fw_err;
-       }
-
-       /* wait for DSP boot completion */
-       sst_dsp_boot(byt->dsp);
-       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
-                                msecs_to_jiffies(IPC_BOOT_MSECS));
-       if (err == 0) {
-               err = -EIO;
-               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
-               goto boot_err;
-       }
-
-       /* show firmware information */
-       sst_dsp_inbox_read(byt->dsp, &init, sizeof(init));
-       dev_info(byt->dev, "FW version: %02x.%02x.%02x.%02x\n",
-                init.fw_version.major, init.fw_version.minor,
-                init.fw_version.build, init.fw_version.type);
-       dev_info(byt->dev, "Build type: %x\n", init.fw_version.type);
-       dev_info(byt->dev, "Build date: %s %s\n",
-                init.build_info.date, init.build_info.time);
-
-       pdata->dsp = byt;
-       byt->fw = byt_sst_fw;
-
-       return 0;
-
-boot_err:
-       sst_dsp_reset(byt->dsp);
-       sst_fw_free(byt_sst_fw);
-fw_err:
-       sst_dsp_free(byt->dsp);
-dsp_err:
-       kthread_stop(byt->tx_thread);
-err_free_msg:
-       kfree(byt->msg);
-
-       return err;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_init);
-
-void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-
-       sst_dsp_reset(byt->dsp);
-       sst_fw_free_all(byt->dsp);
-       sst_dsp_free(byt->dsp);
-       kthread_stop(byt->tx_thread);
-       kfree(byt->msg);
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_free);
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h
deleted file mode 100644 (file)
index 8faff6d..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Intel Baytrail SST IPC Support
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#ifndef __SST_BYT_IPC_H
-#define __SST_BYT_IPC_H
-
-#include <linux/types.h>
-
-struct sst_byt;
-struct sst_byt_stream;
-struct sst_pdata;
-extern struct sst_ops sst_byt_ops;
-
-
-#define SST_BYT_MAILBOX_OFFSET         0x144000
-#define SST_BYT_TIMESTAMP_OFFSET       (SST_BYT_MAILBOX_OFFSET + 0x800)
-
-/**
- * Upfront defined maximum message size that is
- * expected by the in/out communication pipes in FW.
- */
-#define SST_BYT_IPC_MAX_PAYLOAD_SIZE   200
-
-/* stream API */
-struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
-       uint32_t (*get_write_position)(struct sst_byt_stream *stream,
-                                      void *data),
-       void *data);
-
-/* stream configuration */
-int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
-                           int bits);
-int sst_byt_stream_set_channels(struct sst_byt *byt,
-                               struct sst_byt_stream *stream, u8 channels);
-int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
-                           unsigned int rate);
-int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
-                       int codec_type, int stream_type, int operation);
-int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
-                         uint32_t buffer_addr, uint32_t buffer_size);
-int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
-int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
-
-/* stream ALSA trigger operations */
-int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
-                        u32 start_offset);
-int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
-int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
-int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
-
-int sst_byt_get_dsp_position(struct sst_byt *byt,
-                            struct sst_byt_stream *stream, int buffer_size);
-
-/* init */
-int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
-void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
-struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
-int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
-int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
-int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
-
-#endif
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
deleted file mode 100644 (file)
index 224c49c..0000000
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * Intel Baytrail SST PCM Support
- * Copyright (c) 2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "sst-baytrail-ipc.h"
-#include "sst-dsp-priv.h"
-#include "sst-dsp.h"
-
-#define BYT_PCM_COUNT          2
-
-static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_MMAP |
-                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_INTERLEAVED |
-                                 SNDRV_PCM_INFO_PAUSE |
-                                 SNDRV_PCM_INFO_RESUME,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
-                                 SNDRV_PCM_FMTBIT_S24_LE,
-       .period_bytes_min       = 384,
-       .period_bytes_max       = 48000,
-       .periods_min            = 2,
-       .periods_max            = 250,
-       .buffer_bytes_max       = 96000,
-};
-
-/* private data for each PCM DSP stream */
-struct sst_byt_pcm_data {
-       struct sst_byt_stream *stream;
-       struct snd_pcm_substream *substream;
-       struct mutex mutex;
-
-       /* latest DSP DMA hw pointer */
-       u32 hw_ptr;
-
-       struct work_struct work;
-};
-
-/* private data for the driver */
-struct sst_byt_priv_data {
-       /* runtime DSP */
-       struct sst_byt *byt;
-
-       /* DAI data */
-       struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
-
-       /* flag indicating is stream context restore needed after suspend */
-       bool restore_stream;
-};
-
-/* this may get called several times by oss emulation */
-static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-       u32 rate, bits;
-       u8 channels;
-       int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-
-       dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
-
-       ret = sst_byt_stream_type(byt, pcm_data->stream,
-                                 1, 1, !playback);
-       if (ret < 0) {
-               dev_err(rtd->dev, "failed to set stream format %d\n", ret);
-               return ret;
-       }
-
-       rate = params_rate(params);
-       ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
-       if (ret < 0) {
-               dev_err(rtd->dev, "could not set rate %d\n", rate);
-               return ret;
-       }
-
-       bits = snd_pcm_format_width(params_format(params));
-       ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
-       if (ret < 0) {
-               dev_err(rtd->dev, "could not set formats %d\n",
-                       params_rate(params));
-               return ret;
-       }
-
-       channels = (u8)(params_channels(params) & 0xF);
-       ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
-       if (ret < 0) {
-               dev_err(rtd->dev, "could not set channels %d\n",
-                       params_rate(params));
-               return ret;
-       }
-
-       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-
-       ret = sst_byt_stream_buffer(byt, pcm_data->stream,
-                                   substream->dma_buffer.addr,
-                                   params_buffer_bytes(params));
-       if (ret < 0) {
-               dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
-               return ret;
-       }
-
-       ret = sst_byt_stream_commit(byt, pcm_data->stream);
-       if (ret < 0) {
-               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       dev_dbg(rtd->dev, "PCM: hw_free\n");
-       snd_pcm_lib_free_pages(substream);
-
-       return 0;
-}
-
-static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-       int ret;
-
-       /* commit stream using existing stream params */
-       ret = sst_byt_stream_commit(byt, pcm_data->stream);
-       if (ret < 0) {
-               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
-               return ret;
-       }
-
-       sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
-
-       dev_dbg(rtd->dev, "stream context restored at offset %d\n",
-               pcm_data->hw_ptr);
-
-       return 0;
-}
-
-static void sst_byt_pcm_work(struct work_struct *work)
-{
-       struct sst_byt_pcm_data *pcm_data =
-               container_of(work, struct sst_byt_pcm_data, work);
-
-       if (snd_pcm_running(pcm_data->substream))
-               sst_byt_pcm_restore_stream_context(pcm_data->substream);
-}
-
-static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-
-       dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               pcm_data->hw_ptr = 0;
-               sst_byt_stream_start(byt, pcm_data->stream, 0);
-               break;
-       case SNDRV_PCM_TRIGGER_RESUME:
-               if (pdata->restore_stream == true)
-                       schedule_work(&pcm_data->work);
-               else
-                       sst_byt_stream_resume(byt, pcm_data->stream);
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               sst_byt_stream_resume(byt, pcm_data->stream);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               sst_byt_stream_stop(byt, pcm_data->stream);
-               break;
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-               pdata->restore_stream = false;
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               sst_byt_stream_pause(byt, pcm_data->stream);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
-{
-       struct sst_byt_pcm_data *pcm_data = data;
-       struct snd_pcm_substream *substream = pcm_data->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt *byt = pdata->byt;
-       u32 pos, hw_pos;
-
-       hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
-                                         snd_pcm_lib_buffer_bytes(substream));
-       pcm_data->hw_ptr = hw_pos;
-       pos = frames_to_bytes(runtime,
-                             (runtime->control->appl_ptr %
-                              runtime->buffer_size));
-
-       dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
-
-       snd_pcm_period_elapsed(substream);
-       return pos;
-}
-
-static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-
-       dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
-
-       return bytes_to_frames(runtime, pcm_data->hw_ptr);
-}
-
-static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-
-       dev_dbg(rtd->dev, "PCM: open\n");
-
-       mutex_lock(&pcm_data->mutex);
-
-       pcm_data->substream = substream;
-
-       snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
-
-       pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
-                                             byt_notify_pointer, pcm_data);
-       if (pcm_data->stream == NULL) {
-               dev_err(rtd->dev, "failed to create stream\n");
-               mutex_unlock(&pcm_data->mutex);
-               return -EINVAL;
-       }
-
-       mutex_unlock(&pcm_data->mutex);
-       return 0;
-}
-
-static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct sst_byt_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
-       struct sst_byt *byt = pdata->byt;
-       int ret;
-
-       dev_dbg(rtd->dev, "PCM: close\n");
-
-       cancel_work_sync(&pcm_data->work);
-       mutex_lock(&pcm_data->mutex);
-       ret = sst_byt_stream_free(byt, pcm_data->stream);
-       if (ret < 0) {
-               dev_dbg(rtd->dev, "Free stream fail\n");
-               goto out;
-       }
-       pcm_data->stream = NULL;
-
-out:
-       mutex_unlock(&pcm_data->mutex);
-       return ret;
-}
-
-static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
-                           struct vm_area_struct *vma)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       dev_dbg(rtd->dev, "PCM: mmap\n");
-       return snd_pcm_lib_default_mmap(substream, vma);
-}
-
-static struct snd_pcm_ops sst_byt_pcm_ops = {
-       .open           = sst_byt_pcm_open,
-       .close          = sst_byt_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = sst_byt_pcm_hw_params,
-       .hw_free        = sst_byt_pcm_hw_free,
-       .trigger        = sst_byt_pcm_trigger,
-       .pointer        = sst_byt_pcm_pointer,
-       .mmap           = sst_byt_pcm_mmap,
-};
-
-static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_pcm *pcm = rtd->pcm;
-       size_t size;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
-       int ret = 0;
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
-           pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               size = sst_byt_pcm_hardware.buffer_bytes_max;
-               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
-                                                           SNDRV_DMA_TYPE_DEV,
-                                                           pdata->dma_dev,
-                                                           size, size);
-               if (ret) {
-                       dev_err(rtd->dev, "dma buffer allocation failed %d\n",
-                               ret);
-                       return ret;
-               }
-       }
-
-       return ret;
-}
-
-static struct snd_soc_dai_driver byt_dais[] = {
-       {
-               .name  = "Baytrail PCM",
-               .playback = {
-                       .stream_name = "System Playback",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S24_3LE |
-                                  SNDRV_PCM_FMTBIT_S16_LE,
-               },
-               .capture = {
-                       .stream_name = "Analog Capture",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
-               },
-       },
-};
-
-static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
-{
-       struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
-       struct sst_byt_priv_data *priv_data;
-       int i;
-
-       if (!plat_data)
-               return -ENODEV;
-
-       priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
-                                GFP_KERNEL);
-       priv_data->byt = plat_data->dsp;
-       snd_soc_platform_set_drvdata(platform, priv_data);
-
-       for (i = 0; i < BYT_PCM_COUNT; i++) {
-               mutex_init(&priv_data->pcm[i].mutex);
-               INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
-       }
-
-       return 0;
-}
-
-static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
-{
-       return 0;
-}
-
-static struct snd_soc_platform_driver byt_soc_platform = {
-       .probe          = sst_byt_pcm_probe,
-       .remove         = sst_byt_pcm_remove,
-       .ops            = &sst_byt_pcm_ops,
-       .pcm_new        = sst_byt_pcm_new,
-};
-
-static const struct snd_soc_component_driver byt_dai_component = {
-       .name           = "byt-dai",
-};
-
-#ifdef CONFIG_PM
-static int sst_byt_pcm_dev_suspend_late(struct device *dev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-       struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev);
-       int ret;
-
-       dev_dbg(dev, "suspending late\n");
-
-       ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
-       if (ret < 0) {
-               dev_err(dev, "failed to suspend %d\n", ret);
-               return ret;
-       }
-
-       priv_data->restore_stream = true;
-
-       return ret;
-}
-
-static int sst_byt_pcm_dev_resume_early(struct device *dev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-       int ret;
-
-       dev_dbg(dev, "resume early\n");
-
-       /* load fw and boot DSP */
-       ret = sst_byt_dsp_boot(dev, sst_pdata);
-       if (ret)
-               return ret;
-
-       /* wait for FW to finish booting */
-       return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
-}
-
-static const struct dev_pm_ops sst_byt_pm_ops = {
-       .suspend_late = sst_byt_pcm_dev_suspend_late,
-       .resume_early = sst_byt_pcm_dev_resume_early,
-};
-
-#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
-#else
-#define SST_BYT_PM_OPS NULL
-#endif
-
-static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
-       int ret;
-
-       ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
-       if (ret < 0)
-               return -ENODEV;
-
-       ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
-       if (ret < 0)
-               goto err_plat;
-
-       ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
-                                        byt_dais, ARRAY_SIZE(byt_dais));
-       if (ret < 0)
-               goto err_comp;
-
-       return 0;
-
-err_comp:
-       snd_soc_unregister_platform(&pdev->dev);
-err_plat:
-       sst_byt_dsp_free(&pdev->dev, sst_pdata);
-       return ret;
-}
-
-static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
-
-       snd_soc_unregister_platform(&pdev->dev);
-       snd_soc_unregister_component(&pdev->dev);
-       sst_byt_dsp_free(&pdev->dev, sst_pdata);
-
-       return 0;
-}
-
-static struct platform_driver sst_byt_pcm_driver = {
-       .driver = {
-               .name = "baytrail-pcm-audio",
-               .pm = SST_BYT_PM_OPS,
-       },
-
-       .probe = sst_byt_pcm_dev_probe,
-       .remove = sst_byt_pcm_dev_remove,
-};
-module_platform_driver(sst_byt_pcm_driver);
-
-MODULE_AUTHOR("Jarkko Nikula");
-MODULE_DESCRIPTION("Baytrail PCM");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:baytrail-pcm-audio");
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h
deleted file mode 100644 (file)
index b9da030..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Intel Smart Sound Technology
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __SOUND_SOC_SST_DSP_PRIV_H
-#define __SOUND_SOC_SST_DSP_PRIV_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/firmware.h>
-
-struct sst_mem_block;
-struct sst_module;
-struct sst_fw;
-
-/* do we need to remove or keep */
-#define DSP_DRAM_ADDR_OFFSET           0x400000
-
-/*
- * DSP Operations exported by platform Audio DSP driver.
- */
-struct sst_ops {
-       /* DSP core boot / reset */
-       void (*boot)(struct sst_dsp *);
-       void (*reset)(struct sst_dsp *);
-       int (*wake)(struct sst_dsp *);
-       void (*sleep)(struct sst_dsp *);
-       void (*stall)(struct sst_dsp *);
-
-       /* Shim IO */
-       void (*write)(void __iomem *addr, u32 offset, u32 value);
-       u32 (*read)(void __iomem *addr, u32 offset);
-       void (*write64)(void __iomem *addr, u32 offset, u64 value);
-       u64 (*read64)(void __iomem *addr, u32 offset);
-
-       /* DSP I/DRAM IO */
-       void (*ram_read)(struct sst_dsp *sst, void  *dest, void __iomem *src,
-               size_t bytes);
-       void (*ram_write)(struct sst_dsp *sst, void __iomem *dest, void *src,
-               size_t bytes);
-
-       void (*dump)(struct sst_dsp *);
-
-       /* IRQ handlers */
-       irqreturn_t (*irq_handler)(int irq, void *context);
-
-       /* SST init and free */
-       int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata);
-       void (*free)(struct sst_dsp *sst);
-
-       /* FW module parser/loader */
-       int (*parse_fw)(struct sst_fw *sst_fw);
-};
-
-/*
- * Audio DSP memory offsets and addresses.
- */
-struct sst_addr {
-       u32 lpe_base;
-       u32 shim_offset;
-       u32 iram_offset;
-       u32 dram_offset;
-       u32 dsp_iram_offset;
-       u32 dsp_dram_offset;
-       void __iomem *lpe;
-       void __iomem *shim;
-       void __iomem *pci_cfg;
-       void __iomem *fw_ext;
-};
-
-/*
- * Audio DSP Mailbox configuration.
- */
-struct sst_mailbox {
-       void __iomem *in_base;
-       void __iomem *out_base;
-       size_t in_size;
-       size_t out_size;
-};
-
-/*
- * Audio DSP memory block types.
- */
-enum sst_mem_type {
-       SST_MEM_IRAM = 0,
-       SST_MEM_DRAM = 1,
-       SST_MEM_ANY  = 2,
-       SST_MEM_CACHE= 3,
-};
-
-/*
- * Audio DSP Generic Firmware File.
- *
- * SST Firmware files can consist of 1..N modules. This generic structure is
- * used to manage each firmware file and it's modules regardless of SST firmware
- * type. A SST driver may load multiple FW files.
- */
-struct sst_fw {
-       struct sst_dsp *dsp;
-
-       /* base addresses of FW file data */
-       dma_addr_t dmable_fw_paddr;     /* physical address of fw data */
-       void *dma_buf;                  /* virtual address of fw data */
-       u32 size;                       /* size of fw data */
-
-       /* lists */
-       struct list_head list;          /* DSP list of FW */
-       struct list_head module_list;   /* FW list of modules */
-
-       void *private;                  /* core doesn't touch this */
-};
-
-/*
- * Audio DSP Generic Module Template.
- *
- * Used to define and register a new FW module. This data is extracted from
- * FW module header information.
- */
-struct sst_module_template {
-       u32 id;
-       u32 entry;                      /* entry point */
-       u32 scratch_size;
-       u32 persistent_size;
-};
-
-/*
- * Block Allocator - Used to allocate blocks of DSP memory.
- */
-struct sst_block_allocator {
-       u32 id;
-       u32 offset;
-       int size;
-       enum sst_mem_type type;
-};
-
-/*
- * Runtime Module Instance - A module object can be instanciated multiple
- * times within the DSP FW.
- */
-struct sst_module_runtime {
-       struct sst_dsp *dsp;
-       int id;
-       struct sst_module *module;      /* parent module we belong too */
-
-       u32 persistent_offset;          /* private memory offset */
-       void *private;
-
-       struct list_head list;
-       struct list_head block_list;    /* list of blocks used */
-};
-
-/*
- * Runtime Module Context - The runtime context must be manually stored by the
- * driver prior to enter S3 and restored after leaving S3. This should really be
- * part of the memory context saved by the enter D3 message IPC ???
- */
-struct sst_module_runtime_context {
-       dma_addr_t dma_buffer;
-       u32 *buffer;
-};
-
-/*
- * Audio DSP Generic Module.
- *
- * Each Firmware file can consist of 1..N modules. A module can span multiple
- * ADSP memory blocks. The simplest FW will be a file with 1 module. A module
- * can be instanciated multiple times in the DSP.
- */
-struct sst_module {
-       struct sst_dsp *dsp;
-       struct sst_fw *sst_fw;          /* parent FW we belong too */
-
-       /* module configuration */
-       u32 id;
-       u32 entry;                      /* module entry point */
-       s32 offset;                     /* module offset in firmware file */
-       u32 size;                       /* module size */
-       u32 scratch_size;               /* global scratch memory required */
-       u32 persistent_size;            /* private memory required */
-       enum sst_mem_type type;         /* destination memory type */
-       u32 data_offset;                /* offset in ADSP memory space */
-       void *data;                     /* module data */
-
-       /* runtime */
-       u32 usage_count;                /* can be unloaded if count == 0 */
-       void *private;                  /* core doesn't touch this */
-
-       /* lists */
-       struct list_head block_list;    /* Module list of blocks in use */
-       struct list_head list;          /* DSP list of modules */
-       struct list_head list_fw;       /* FW list of modules */
-       struct list_head runtime_list;  /* list of runtime module objects*/
-};
-
-/*
- * SST Memory Block operations.
- */
-struct sst_block_ops {
-       int (*enable)(struct sst_mem_block *block);
-       int (*disable)(struct sst_mem_block *block);
-};
-
-/*
- * SST Generic Memory Block.
- *
- * SST ADP  memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be
- * power gated.
- */
-struct sst_mem_block {
-       struct sst_dsp *dsp;
-       struct sst_module *module;      /* module that uses this block */
-
-       /* block config */
-       u32 offset;                     /* offset from base */
-       u32 size;                       /* block size */
-       u32 index;                      /* block index 0..N */
-       enum sst_mem_type type;         /* block memory type IRAM/DRAM */
-       struct sst_block_ops *ops;      /* block operations, if any */
-
-       /* block status */
-       u32 bytes_used;                 /* bytes in use by modules */
-       void *private;                  /* generic core does not touch this */
-       int users;                      /* number of modules using this block */
-
-       /* block lists */
-       struct list_head module_list;   /* Module list of blocks */
-       struct list_head list;          /* Map list of free/used blocks */
-};
-
-/*
- * Generic SST Shim Interface.
- */
-struct sst_dsp {
-
-       /* runtime */
-       struct sst_dsp_device *sst_dev;
-       spinlock_t spinlock;    /* IPC locking */
-       struct mutex mutex;     /* DSP FW lock */
-       struct device *dev;
-       struct device *dma_dev;
-       void *thread_context;
-       int irq;
-       u32 id;
-
-       /* list of free and used ADSP memory blocks */
-       struct list_head used_block_list;
-       struct list_head free_block_list;
-
-       /* operations */
-       struct sst_ops *ops;
-
-       /* debug FS */
-       struct dentry *debugfs_root;
-
-       /* base addresses */
-       struct sst_addr addr;
-
-       /* mailbox */
-       struct sst_mailbox mailbox;
-
-       /* SST FW files loaded and their modules */
-       struct list_head module_list;
-       struct list_head fw_list;
-
-       /* scratch buffer */
-       struct list_head scratch_block_list;
-       u32 scratch_offset;
-       u32 scratch_size;
-
-       /* platform data */
-       struct sst_pdata *pdata;
-
-       /* DMA FW loading */
-       struct sst_dma *dma;
-       bool fw_use_dma;
-};
-
-/* Size optimised DRAM/IRAM memcpy */
-static inline void sst_dsp_write(struct sst_dsp *sst, void *src,
-       u32 dest_offset, size_t bytes)
-{
-       sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes);
-}
-
-static inline void sst_dsp_read(struct sst_dsp *sst, void *dest,
-       u32 src_offset, size_t bytes)
-{
-       sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes);
-}
-
-static inline void *sst_dsp_get_thread_context(struct sst_dsp *sst)
-{
-       return sst->thread_context;
-}
-
-/* Create/Free FW files - can contain multiple modules */
-struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
-       const struct firmware *fw, void *private);
-void sst_fw_free(struct sst_fw *sst_fw);
-void sst_fw_free_all(struct sst_dsp *dsp);
-int sst_fw_reload(struct sst_fw *sst_fw);
-void sst_fw_unload(struct sst_fw *sst_fw);
-
-/* Create/Free firmware modules */
-struct sst_module *sst_module_new(struct sst_fw *sst_fw,
-       struct sst_module_template *template, void *private);
-void sst_module_free(struct sst_module *module);
-struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
-int sst_module_alloc_blocks(struct sst_module *module);
-int sst_module_free_blocks(struct sst_module *module);
-
-/* Create/Free firmware module runtime instances */
-struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module,
-       int id, void *private);
-void sst_module_runtime_free(struct sst_module_runtime *runtime);
-struct sst_module_runtime *sst_module_runtime_get_from_id(
-       struct sst_module *module, u32 id);
-int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
-       int offset);
-int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime);
-int sst_module_runtime_save(struct sst_module_runtime *runtime,
-       struct sst_module_runtime_context *context);
-int sst_module_runtime_restore(struct sst_module_runtime *runtime,
-       struct sst_module_runtime_context *context);
-
-/* generic block allocation */
-int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba,
-       struct list_head *block_list);
-int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list);
-
-/* scratch allocation */
-int sst_block_alloc_scratch(struct sst_dsp *dsp);
-void sst_block_free_scratch(struct sst_dsp *dsp);
-
-/* Register the DSPs memory blocks - would be nice to read from ACPI */
-struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
-       u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
-       void *private);
-void sst_mem_block_unregister_all(struct sst_dsp *dsp);
-
-/* Create/Free DMA resources */
-int sst_dma_new(struct sst_dsp *sst);
-void sst_dma_free(struct sst_dma *dma);
-
-u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
-       enum sst_mem_type type);
-#endif
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c
deleted file mode 100644 (file)
index 64e9421..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Intel Smart Sound Technology (SST) DSP Core Driver
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/intel-sst.h>
-
-/* Internal generic low-level SST IO functions - can be overidden */
-void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
-{
-       writel(value, addr + offset);
-}
-EXPORT_SYMBOL_GPL(sst_shim32_write);
-
-u32 sst_shim32_read(void __iomem *addr, u32 offset)
-{
-       return readl(addr + offset);
-}
-EXPORT_SYMBOL_GPL(sst_shim32_read);
-
-void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
-{
-       memcpy_toio(addr + offset, &value, sizeof(value));
-}
-EXPORT_SYMBOL_GPL(sst_shim32_write64);
-
-u64 sst_shim32_read64(void __iomem *addr, u32 offset)
-{
-       u64 val;
-
-       memcpy_fromio(&val, addr + offset, sizeof(val));
-       return val;
-}
-EXPORT_SYMBOL_GPL(sst_shim32_read64);
-
-static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest,
-       u32 *src, size_t bytes)
-{
-       int i, words = bytes >> 2;
-
-       for (i = 0; i < words; i++)
-               writel(src[i], dest + i);
-}
-
-static inline void _sst_memcpy_fromio_32(u32 *dest,
-       const volatile __iomem u32 *src, size_t bytes)
-{
-       int i, words = bytes >> 2;
-
-       for (i = 0; i < words; i++)
-               dest[i] = readl(src + i);
-}
-
-void sst_memcpy_toio_32(struct sst_dsp *sst,
-       void __iomem *dest, void *src, size_t bytes)
-{
-       _sst_memcpy_toio_32(dest, src, bytes);
-}
-EXPORT_SYMBOL_GPL(sst_memcpy_toio_32);
-
-void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest,
-       void __iomem *src, size_t bytes)
-{
-       _sst_memcpy_fromio_32(dest, src, bytes);
-}
-EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32);
-
-/* Public API */
-void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       sst->ops->write(sst->addr.shim, offset, value);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
-
-u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
-{
-       unsigned long flags;
-       u32 val;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       val = sst->ops->read(sst->addr.shim, offset);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       return val;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
-
-void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       sst->ops->write64(sst->addr.shim, offset, value);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_write64);
-
-u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset)
-{
-       unsigned long flags;
-       u64 val;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       val = sst->ops->read64(sst->addr.shim, offset);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       return val;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_read64);
-
-void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
-{
-       sst->ops->write(sst->addr.shim, offset, value);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
-
-u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
-{
-       return sst->ops->read(sst->addr.shim, offset);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
-
-void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value)
-{
-       sst->ops->write64(sst->addr.shim, offset, value);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked);
-
-u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset)
-{
-       return sst->ops->read64(sst->addr.shim, offset);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked);
-
-int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
-                               u32 mask, u32 value)
-{
-       bool change;
-       unsigned int old, new;
-       u32 ret;
-
-       ret = sst_dsp_shim_read_unlocked(sst, offset);
-
-       old = ret;
-       new = (old & (~mask)) | (value & mask);
-
-       change = (old != new);
-       if (change)
-               sst_dsp_shim_write_unlocked(sst, offset, new);
-
-       return change;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
-
-int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
-                               u64 mask, u64 value)
-{
-       bool change;
-       u64 old, new;
-
-       old = sst_dsp_shim_read64_unlocked(sst, offset);
-
-       new = (old & (~mask)) | (value & mask);
-
-       change = (old != new);
-       if (change)
-               sst_dsp_shim_write64_unlocked(sst, offset, new);
-
-       return change;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
-
-int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
-                               u32 mask, u32 value)
-{
-       unsigned long flags;
-       bool change;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-       return change;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
-
-int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
-                               u64 mask, u64 value)
-{
-       unsigned long flags;
-       bool change;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-       return change;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
-
-void sst_dsp_dump(struct sst_dsp *sst)
-{
-       if (sst->ops->dump)
-               sst->ops->dump(sst);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_dump);
-
-void sst_dsp_reset(struct sst_dsp *sst)
-{
-       if (sst->ops->reset)
-               sst->ops->reset(sst);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_reset);
-
-int sst_dsp_boot(struct sst_dsp *sst)
-{
-       if (sst->ops->boot)
-               sst->ops->boot(sst);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_boot);
-
-int sst_dsp_wake(struct sst_dsp *sst)
-{
-       if (sst->ops->wake)
-               return sst->ops->wake(sst);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_wake);
-
-void sst_dsp_sleep(struct sst_dsp *sst)
-{
-       if (sst->ops->sleep)
-               sst->ops->sleep(sst);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_sleep);
-
-void sst_dsp_stall(struct sst_dsp *sst)
-{
-       if (sst->ops->stall)
-               sst->ops->stall(sst);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_stall);
-
-void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
-{
-       sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
-       trace_sst_ipc_msg_tx(msg);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx);
-
-u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp)
-{
-       u32 msg;
-
-       msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
-       trace_sst_ipc_msg_rx(msg);
-
-       return msg;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx);
-
-int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
-       u32 outbox_offset, size_t outbox_size)
-{
-       sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
-       sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
-       sst->mailbox.in_size = inbox_size;
-       sst->mailbox.out_size = outbox_size;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
-
-void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
-{
-       u32 i;
-
-       trace_sst_ipc_outbox_write(bytes);
-
-       memcpy_toio(sst->mailbox.out_base, message, bytes);
-
-       for (i = 0; i < bytes; i += 4)
-               trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
-}
-EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
-
-void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
-{
-       u32 i;
-
-       trace_sst_ipc_outbox_read(bytes);
-
-       memcpy_fromio(message, sst->mailbox.out_base, bytes);
-
-       for (i = 0; i < bytes; i += 4)
-               trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
-}
-EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
-
-void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
-{
-       u32 i;
-
-       trace_sst_ipc_inbox_write(bytes);
-
-       memcpy_toio(sst->mailbox.in_base, message, bytes);
-
-       for (i = 0; i < bytes; i += 4)
-               trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
-}
-EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
-
-void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
-{
-       u32 i;
-
-       trace_sst_ipc_inbox_read(bytes);
-
-       memcpy_fromio(message, sst->mailbox.in_base, bytes);
-
-       for (i = 0; i < bytes; i += 4)
-               trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
-}
-EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
-
-struct sst_dsp *sst_dsp_new(struct device *dev,
-       struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
-{
-       struct sst_dsp *sst;
-       int err;
-
-       dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
-
-       sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
-       if (sst == NULL)
-               return NULL;
-
-       spin_lock_init(&sst->spinlock);
-       mutex_init(&sst->mutex);
-       sst->dev = dev;
-       sst->dma_dev = pdata->dma_dev;
-       sst->thread_context = sst_dev->thread_context;
-       sst->sst_dev = sst_dev;
-       sst->id = pdata->id;
-       sst->irq = pdata->irq;
-       sst->ops = sst_dev->ops;
-       sst->pdata = pdata;
-       INIT_LIST_HEAD(&sst->used_block_list);
-       INIT_LIST_HEAD(&sst->free_block_list);
-       INIT_LIST_HEAD(&sst->module_list);
-       INIT_LIST_HEAD(&sst->fw_list);
-       INIT_LIST_HEAD(&sst->scratch_block_list);
-
-       /* Initialise SST Audio DSP */
-       if (sst->ops->init) {
-               err = sst->ops->init(sst, pdata);
-               if (err < 0)
-                       return NULL;
-       }
-
-       /* Register the ISR */
-       err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
-               sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
-       if (err)
-               goto irq_err;
-
-       err = sst_dma_new(sst);
-       if (err)
-               dev_warn(dev, "sst_dma_new failed %d\n", err);
-
-       return sst;
-
-irq_err:
-       if (sst->ops->free)
-               sst->ops->free(sst);
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_new);
-
-void sst_dsp_free(struct sst_dsp *sst)
-{
-       free_irq(sst->irq, sst);
-       if (sst->ops->free)
-               sst->ops->free(sst);
-
-       sst_dma_free(sst->dma);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_free);
-
-/* Module information */
-MODULE_AUTHOR("Liam Girdwood");
-MODULE_DESCRIPTION("Intel SST Core");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h
deleted file mode 100644 (file)
index f291e32..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Intel Smart Sound Technology (SST) Core
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __SOUND_SOC_SST_DSP_H
-#define __SOUND_SOC_SST_DSP_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-
-/* SST Device IDs  */
-#define SST_DEV_ID_LYNX_POINT          0x33C8
-#define SST_DEV_ID_WILDCAT_POINT       0x3438
-#define SST_DEV_ID_BYT                 0x0F28
-
-/* Supported SST DMA Devices */
-#define SST_DMA_TYPE_DW                1
-#define SST_DMA_TYPE_MID       2
-
-/* autosuspend delay 5s*/
-#define SST_RUNTIME_SUSPEND_DELAY      (5 * 1000)
-
-/* SST Shim register map
- * The register naming can differ between products. Some products also
- * contain extra functionality.
- */
-#define SST_CSR                        0x00
-#define SST_PISR               0x08
-#define SST_PIMR               0x10
-#define SST_ISRX               0x18
-#define SST_ISRD               0x20
-#define SST_IMRX               0x28
-#define SST_IMRD               0x30
-#define SST_IPCX               0x38 /* IPC IA -> SST */
-#define SST_IPCD               0x40 /* IPC SST -> IA */
-#define SST_ISRSC              0x48
-#define SST_ISRLPESC           0x50
-#define SST_IMRSC              0x58
-#define SST_IMRLPESC           0x60
-#define SST_IPCSC              0x68
-#define SST_IPCLPESC           0x70
-#define SST_CLKCTL             0x78
-#define SST_CSR2               0x80
-#define SST_LTRC               0xE0
-#define SST_HMDC               0xE8
-
-#define SST_SHIM_BEGIN         SST_CSR
-#define SST_SHIM_END           SST_HDMC
-
-#define SST_DBGO               0xF0
-
-#define SST_SHIM_SIZE          0x100
-#define SST_PWMCTRL             0x1000
-
-/* SST Shim Register bits
- * The register bit naming can differ between products. Some products also
- * contain extra functionality.
- */
-
-/* CSR / CS */
-#define SST_CSR_RST            (0x1 << 1)
-#define SST_CSR_SBCS0          (0x1 << 2)
-#define SST_CSR_SBCS1          (0x1 << 3)
-#define SST_CSR_DCS(x)         (x << 4)
-#define SST_CSR_DCS_MASK       (0x7 << 4)
-#define SST_CSR_STALL          (0x1 << 10)
-#define SST_CSR_S0IOCS         (0x1 << 21)
-#define SST_CSR_S1IOCS         (0x1 << 23)
-#define SST_CSR_LPCS           (0x1 << 31)
-#define SST_CSR_24MHZ_LPCS     (SST_CSR_SBCS0 | SST_CSR_SBCS1 | SST_CSR_LPCS)
-#define SST_CSR_24MHZ_NO_LPCS  (SST_CSR_SBCS0 | SST_CSR_SBCS1)
-#define SST_BYT_CSR_RST                (0x1 << 0)
-#define SST_BYT_CSR_VECTOR_SEL (0x1 << 1)
-#define SST_BYT_CSR_STALL      (0x1 << 2)
-#define SST_BYT_CSR_PWAITMODE  (0x1 << 3)
-
-/*  ISRX / ISC */
-#define SST_ISRX_BUSY          (0x1 << 1)
-#define SST_ISRX_DONE          (0x1 << 0)
-#define SST_BYT_ISRX_REQUEST   (0x1 << 1)
-
-/*  ISRD / ISD */
-#define SST_ISRD_BUSY          (0x1 << 1)
-#define SST_ISRD_DONE          (0x1 << 0)
-
-/* IMRX / IMC */
-#define SST_IMRX_BUSY          (0x1 << 1)
-#define SST_IMRX_DONE          (0x1 << 0)
-#define SST_BYT_IMRX_REQUEST   (0x1 << 1)
-
-/* IMRD / IMD */
-#define SST_IMRD_DONE          (0x1 << 0)
-#define SST_IMRD_BUSY          (0x1 << 1)
-#define SST_IMRD_SSP0          (0x1 << 16)
-#define SST_IMRD_DMAC0         (0x1 << 21)
-#define SST_IMRD_DMAC1         (0x1 << 22)
-#define SST_IMRD_DMAC          (SST_IMRD_DMAC0 | SST_IMRD_DMAC1)
-
-/*  IPCX / IPCC */
-#define        SST_IPCX_DONE           (0x1 << 30)
-#define        SST_IPCX_BUSY           (0x1 << 31)
-#define SST_BYT_IPCX_DONE      ((u64)0x1 << 62)
-#define SST_BYT_IPCX_BUSY      ((u64)0x1 << 63)
-
-/*  IPCD */
-#define        SST_IPCD_DONE           (0x1 << 30)
-#define        SST_IPCD_BUSY           (0x1 << 31)
-#define SST_BYT_IPCD_DONE      ((u64)0x1 << 62)
-#define SST_BYT_IPCD_BUSY      ((u64)0x1 << 63)
-
-/* CLKCTL */
-#define SST_CLKCTL_SMOS(x)     (x << 24)
-#define SST_CLKCTL_MASK                (3 << 24)
-#define SST_CLKCTL_DCPLCG      (1 << 18)
-#define SST_CLKCTL_SCOE1       (1 << 17)
-#define SST_CLKCTL_SCOE0       (1 << 16)
-
-/* CSR2 / CS2 */
-#define SST_CSR2_SDFD_SSP0     (1 << 1)
-#define SST_CSR2_SDFD_SSP1     (1 << 2)
-
-/* LTRC */
-#define SST_LTRC_VAL(x)                (x << 0)
-
-/* HMDC */
-#define SST_HMDC_HDDA0(x)      (x << 0)
-#define SST_HMDC_HDDA1(x)      (x << 7)
-#define SST_HMDC_HDDA_E0_CH0   1
-#define SST_HMDC_HDDA_E0_CH1   2
-#define SST_HMDC_HDDA_E0_CH2   4
-#define SST_HMDC_HDDA_E0_CH3   8
-#define SST_HMDC_HDDA_E1_CH0   SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH0)
-#define SST_HMDC_HDDA_E1_CH1   SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH1)
-#define SST_HMDC_HDDA_E1_CH2   SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH2)
-#define SST_HMDC_HDDA_E1_CH3   SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH3)
-#define SST_HMDC_HDDA_E0_ALLCH (SST_HMDC_HDDA_E0_CH0 | SST_HMDC_HDDA_E0_CH1 | \
-                                SST_HMDC_HDDA_E0_CH2 | SST_HMDC_HDDA_E0_CH3)
-#define SST_HMDC_HDDA_E1_ALLCH (SST_HMDC_HDDA_E1_CH0 | SST_HMDC_HDDA_E1_CH1 | \
-                                SST_HMDC_HDDA_E1_CH2 | SST_HMDC_HDDA_E1_CH3)
-
-
-/* SST Vendor Defined Registers and bits */
-#define SST_VDRTCTL0           0xa0
-#define SST_VDRTCTL1           0xa4
-#define SST_VDRTCTL2           0xa8
-#define SST_VDRTCTL3           0xaC
-
-/* VDRTCTL0 */
-#define SST_VDRTCL0_D3PGD              (1 << 0)
-#define SST_VDRTCL0_D3SRAMPGD          (1 << 1)
-#define SST_VDRTCL0_DSRAMPGE_SHIFT     12
-#define SST_VDRTCL0_DSRAMPGE_MASK      (0xfffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
-#define SST_VDRTCL0_ISRAMPGE_SHIFT     2
-#define SST_VDRTCL0_ISRAMPGE_MASK      (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
-
-/* VDRTCTL2 */
-#define SST_VDRTCL2_DCLCGE             (1 << 1)
-#define SST_VDRTCL2_DTCGE              (1 << 10)
-#define SST_VDRTCL2_APLLSE_MASK                (1 << 31)
-
-/* PMCS */
-#define SST_PMCS               0x84
-#define SST_PMCS_PS_MASK       0x3
-
-struct sst_dsp;
-
-/*
- * SST Device.
- *
- * This structure is populated by the SST core driver.
- */
-struct sst_dsp_device {
-       /* Mandatory fields */
-       struct sst_ops *ops;
-       irqreturn_t (*thread)(int irq, void *context);
-       void *thread_context;
-};
-
-/*
- * SST Platform Data.
- */
-struct sst_pdata {
-       /* ACPI data */
-       u32 lpe_base;
-       u32 lpe_size;
-       u32 pcicfg_base;
-       u32 pcicfg_size;
-       u32 fw_base;
-       u32 fw_size;
-       int irq;
-
-       /* Firmware */
-       const struct firmware *fw;
-
-       /* DMA */
-       u32 dma_base;
-       u32 dma_size;
-       int dma_engine;
-       struct device *dma_dev;
-
-       /* DSP */
-       u32 id;
-       void *dsp;
-};
-
-/* Initialization */
-struct sst_dsp *sst_dsp_new(struct device *dev,
-       struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
-void sst_dsp_free(struct sst_dsp *sst);
-
-/* SHIM Read / Write */
-void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
-u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset);
-int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
-                               u32 mask, u32 value);
-void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value);
-u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset);
-int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
-                               u64 mask, u64 value);
-
-/* SHIM Read / Write Unlocked for callers already holding sst lock */
-void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
-u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset);
-int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
-                               u32 mask, u32 value);
-void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value);
-u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset);
-int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
-                                       u64 mask, u64 value);
-
-/* Internal generic low-level SST IO functions - can be overidden */
-void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
-u32 sst_shim32_read(void __iomem *addr, u32 offset);
-void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value);
-u64 sst_shim32_read64(void __iomem *addr, u32 offset);
-void sst_memcpy_toio_32(struct sst_dsp *sst,
-                       void __iomem *dest, void *src, size_t bytes);
-void sst_memcpy_fromio_32(struct sst_dsp *sst,
-                         void *dest, void __iomem *src, size_t bytes);
-
-/* DSP reset & boot */
-void sst_dsp_reset(struct sst_dsp *sst);
-int sst_dsp_boot(struct sst_dsp *sst);
-int sst_dsp_wake(struct sst_dsp *sst);
-void sst_dsp_sleep(struct sst_dsp *sst);
-void sst_dsp_stall(struct sst_dsp *sst);
-
-/* DMA */
-int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id);
-void sst_dsp_dma_put_channel(struct sst_dsp *dsp);
-int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr,
-       dma_addr_t src_addr, size_t size);
-int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr,
-       dma_addr_t src_addr, size_t size);
-
-/* Msg IO */
-void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);
-u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp);
-
-/* Mailbox management */
-int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset,
-       size_t inbox_size, u32 outbox_offset, size_t outbox_size);
-void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
-void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
-void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
-void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
-void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes);
-
-/* Debug */
-void sst_dsp_dump(struct sst_dsp *sst);
-
-#endif
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c
deleted file mode 100644 (file)
index 5f71ef6..0000000
+++ /dev/null
@@ -1,1205 +0,0 @@
-/*
- * Intel SST Firmware Loader
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/firmware.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/pci.h>
-#include <linux/acpi.h>
-
-/* supported DMA engine drivers */
-#include <linux/platform_data/dma-dw.h>
-#include <linux/dma/dw.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-
-#define SST_DMA_RESOURCES      2
-#define SST_DSP_DMA_MAX_BURST  0x3
-#define SST_HSW_BLOCK_ANY      0xffffffff
-
-#define SST_HSW_MASK_DMA_ADDR_DSP 0xfff00000
-
-struct sst_dma {
-       struct sst_dsp *sst;
-
-       struct dw_dma_chip *chip;
-
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *ch;
-};
-
-static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
-{
-       /* __iowrite32_copy use 32bit size values so divide by 4 */
-       __iowrite32_copy((void *)dest, src, bytes/4);
-}
-
-static void sst_dma_transfer_complete(void *arg)
-{
-       struct sst_dsp *sst = (struct sst_dsp *)arg;
-
-       dev_dbg(sst->dev, "DMA: callback\n");
-}
-
-static int sst_dsp_dma_copy(struct sst_dsp *sst, dma_addr_t dest_addr,
-       dma_addr_t src_addr, size_t size)
-{
-       struct dma_async_tx_descriptor *desc;
-       struct sst_dma *dma = sst->dma;
-
-       if (dma->ch == NULL) {
-               dev_err(sst->dev, "error: no DMA channel\n");
-               return -ENODEV;
-       }
-
-       dev_dbg(sst->dev, "DMA: src: 0x%lx dest 0x%lx size %zu\n",
-               (unsigned long)src_addr, (unsigned long)dest_addr, size);
-
-       desc = dma->ch->device->device_prep_dma_memcpy(dma->ch, dest_addr,
-               src_addr, size, DMA_CTRL_ACK);
-       if (!desc){
-               dev_err(sst->dev, "error: dma prep memcpy failed\n");
-               return -EINVAL;
-       }
-
-       desc->callback = sst_dma_transfer_complete;
-       desc->callback_param = sst;
-
-       desc->tx_submit(desc);
-       dma_wait_for_async_tx(desc);
-
-       return 0;
-}
-
-/* copy to DSP */
-int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr,
-       dma_addr_t src_addr, size_t size)
-{
-       return sst_dsp_dma_copy(sst, dest_addr | SST_HSW_MASK_DMA_ADDR_DSP,
-                       src_addr, size);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_dma_copyto);
-
-/* copy from DSP */
-int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr,
-       dma_addr_t src_addr, size_t size)
-{
-       return sst_dsp_dma_copy(sst, dest_addr,
-               src_addr | SST_HSW_MASK_DMA_ADDR_DSP, size);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_dma_copyfrom);
-
-/* remove module from memory - callers hold locks */
-static void block_list_remove(struct sst_dsp *dsp,
-       struct list_head *block_list)
-{
-       struct sst_mem_block *block, *tmp;
-       int err;
-
-       /* disable each block  */
-       list_for_each_entry(block, block_list, module_list) {
-
-               if (block->ops && block->ops->disable) {
-                       err = block->ops->disable(block);
-                       if (err < 0)
-                               dev_err(dsp->dev,
-                                       "error: cant disable block %d:%d\n",
-                                       block->type, block->index);
-               }
-       }
-
-       /* mark each block as free */
-       list_for_each_entry_safe(block, tmp, block_list, module_list) {
-               list_del(&block->module_list);
-               list_move(&block->list, &dsp->free_block_list);
-               dev_dbg(dsp->dev, "block freed %d:%d at offset 0x%x\n",
-                       block->type, block->index, block->offset);
-       }
-}
-
-/* prepare the memory block to receive data from host - callers hold locks */
-static int block_list_prepare(struct sst_dsp *dsp,
-       struct list_head *block_list)
-{
-       struct sst_mem_block *block;
-       int ret = 0;
-
-       /* enable each block so that's it'e ready for data */
-       list_for_each_entry(block, block_list, module_list) {
-
-               if (block->ops && block->ops->enable && !block->users) {
-                       ret = block->ops->enable(block);
-                       if (ret < 0) {
-                               dev_err(dsp->dev,
-                                       "error: cant disable block %d:%d\n",
-                                       block->type, block->index);
-                               goto err;
-                       }
-               }
-       }
-       return ret;
-
-err:
-       list_for_each_entry(block, block_list, module_list) {
-               if (block->ops && block->ops->disable)
-                       block->ops->disable(block);
-       }
-       return ret;
-}
-
-static struct dw_dma_platform_data dw_pdata = {
-       .is_private = 1,
-       .chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
-       .chan_priority = CHAN_PRIORITY_ASCENDING,
-};
-
-static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem,
-       int irq)
-{
-       struct dw_dma_chip *chip;
-       int err;
-
-       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
-       if (!chip)
-               return ERR_PTR(-ENOMEM);
-
-       chip->irq = irq;
-       chip->regs = devm_ioremap_resource(dev, mem);
-       if (IS_ERR(chip->regs))
-               return ERR_CAST(chip->regs);
-
-       err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
-       if (err)
-               return ERR_PTR(err);
-
-       chip->dev = dev;
-       err = dw_dma_probe(chip, &dw_pdata);
-       if (err)
-               return ERR_PTR(err);
-
-       return chip;
-}
-
-static void dw_remove(struct dw_dma_chip *chip)
-{
-       dw_dma_remove(chip);
-}
-
-static bool dma_chan_filter(struct dma_chan *chan, void *param)
-{
-       struct sst_dsp *dsp = (struct sst_dsp *)param;
-
-       return chan->device->dev == dsp->dma_dev;
-}
-
-int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id)
-{
-       struct sst_dma *dma = dsp->dma;
-       struct dma_slave_config slave;
-       dma_cap_mask_t mask;
-       int ret;
-
-       /* The Intel MID DMA engine driver needs the slave config set but
-        * Synopsis DMA engine driver safely ignores the slave config */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       dma_cap_set(DMA_MEMCPY, mask);
-
-       dma->ch = dma_request_channel(mask, dma_chan_filter, dsp);
-       if (dma->ch == NULL) {
-               dev_err(dsp->dev, "error: DMA request channel failed\n");
-               return -EIO;
-       }
-
-       memset(&slave, 0, sizeof(slave));
-       slave.direction = DMA_MEM_TO_DEV;
-       slave.src_addr_width =
-               slave.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       slave.src_maxburst = slave.dst_maxburst = SST_DSP_DMA_MAX_BURST;
-
-       ret = dmaengine_slave_config(dma->ch, &slave);
-       if (ret) {
-               dev_err(dsp->dev, "error: unable to set DMA slave config %d\n",
-                       ret);
-               dma_release_channel(dma->ch);
-               dma->ch = NULL;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_dma_get_channel);
-
-void sst_dsp_dma_put_channel(struct sst_dsp *dsp)
-{
-       struct sst_dma *dma = dsp->dma;
-
-       if (!dma->ch)
-               return;
-
-       dma_release_channel(dma->ch);
-       dma->ch = NULL;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_dma_put_channel);
-
-int sst_dma_new(struct sst_dsp *sst)
-{
-       struct sst_pdata *sst_pdata = sst->pdata;
-       struct sst_dma *dma;
-       struct resource mem;
-       const char *dma_dev_name;
-       int ret = 0;
-
-       /* configure the correct platform data for whatever DMA engine
-       * is attached to the ADSP IP. */
-       switch (sst->pdata->dma_engine) {
-       case SST_DMA_TYPE_DW:
-               dma_dev_name = "dw_dmac";
-               break;
-       case SST_DMA_TYPE_MID:
-               dma_dev_name = "Intel MID DMA";
-               break;
-       default:
-               dev_err(sst->dev, "error: invalid DMA engine %d\n",
-                       sst->pdata->dma_engine);
-               return -EINVAL;
-       }
-
-       dma = devm_kzalloc(sst->dev, sizeof(struct sst_dma), GFP_KERNEL);
-       if (!dma)
-               return -ENOMEM;
-
-       dma->sst = sst;
-
-       memset(&mem, 0, sizeof(mem));
-
-       mem.start = sst->addr.lpe_base + sst_pdata->dma_base;
-       mem.end   = sst->addr.lpe_base + sst_pdata->dma_base + sst_pdata->dma_size - 1;
-       mem.flags = IORESOURCE_MEM;
-
-       /* now register DMA engine device */
-       dma->chip = dw_probe(sst->dma_dev, &mem, sst_pdata->irq);
-       if (IS_ERR(dma->chip)) {
-               dev_err(sst->dev, "error: DMA device register failed\n");
-               ret = PTR_ERR(dma->chip);
-               goto err_dma_dev;
-       }
-
-       sst->dma = dma;
-       sst->fw_use_dma = true;
-       return 0;
-
-err_dma_dev:
-       devm_kfree(sst->dev, dma);
-       return ret;
-}
-EXPORT_SYMBOL(sst_dma_new);
-
-void sst_dma_free(struct sst_dma *dma)
-{
-
-       if (dma == NULL)
-               return;
-
-       if (dma->ch)
-               dma_release_channel(dma->ch);
-
-       if (dma->chip)
-               dw_remove(dma->chip);
-
-}
-EXPORT_SYMBOL(sst_dma_free);
-
-/* create new generic firmware object */
-struct sst_fw *sst_fw_new(struct sst_dsp *dsp, 
-       const struct firmware *fw, void *private)
-{
-       struct sst_fw *sst_fw;
-       int err;
-
-       if (!dsp->ops->parse_fw)
-               return NULL;
-
-       sst_fw = kzalloc(sizeof(*sst_fw), GFP_KERNEL);
-       if (sst_fw == NULL)
-               return NULL;
-
-       sst_fw->dsp = dsp;
-       sst_fw->private = private;
-       sst_fw->size = fw->size;
-
-       /* allocate DMA buffer to store FW data */
-       sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size,
-                               &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
-       if (!sst_fw->dma_buf) {
-               dev_err(dsp->dev, "error: DMA alloc failed\n");
-               kfree(sst_fw);
-               return NULL;
-       }
-
-       /* copy FW data to DMA-able memory */
-       memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size);
-
-       if (dsp->fw_use_dma) {
-               err = sst_dsp_dma_get_channel(dsp, 0);
-               if (err < 0)
-                       goto chan_err;
-       }
-
-       /* call core specific FW paser to load FW data into DSP */
-       err = dsp->ops->parse_fw(sst_fw);
-       if (err < 0) {
-               dev_err(dsp->dev, "error: parse fw failed %d\n", err);
-               goto parse_err;
-       }
-
-       if (dsp->fw_use_dma)
-               sst_dsp_dma_put_channel(dsp);
-
-       mutex_lock(&dsp->mutex);
-       list_add(&sst_fw->list, &dsp->fw_list);
-       mutex_unlock(&dsp->mutex);
-
-       return sst_fw;
-
-parse_err:
-       if (dsp->fw_use_dma)
-               sst_dsp_dma_put_channel(dsp);
-chan_err:
-       dma_free_coherent(dsp->dma_dev, sst_fw->size,
-                               sst_fw->dma_buf,
-                               sst_fw->dmable_fw_paddr);
-       sst_fw->dma_buf = NULL;
-       kfree(sst_fw);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(sst_fw_new);
-
-int sst_fw_reload(struct sst_fw *sst_fw)
-{
-       struct sst_dsp *dsp = sst_fw->dsp;
-       int ret;
-
-       dev_dbg(dsp->dev, "reloading firmware\n");
-
-       /* call core specific FW paser to load FW data into DSP */
-       ret = dsp->ops->parse_fw(sst_fw);
-       if (ret < 0)
-               dev_err(dsp->dev, "error: parse fw failed %d\n", ret);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_fw_reload);
-
-void sst_fw_unload(struct sst_fw *sst_fw)
-{
-       struct sst_dsp *dsp = sst_fw->dsp;
-       struct sst_module *module, *mtmp;
-       struct sst_module_runtime *runtime, *rtmp;
-
-       dev_dbg(dsp->dev, "unloading firmware\n");
-
-       mutex_lock(&dsp->mutex);
-
-       /* check module by module */
-       list_for_each_entry_safe(module, mtmp, &dsp->module_list, list) {
-               if (module->sst_fw == sst_fw) {
-
-                       /* remove runtime modules */
-                       list_for_each_entry_safe(runtime, rtmp, &module->runtime_list, list) {
-
-                               block_list_remove(dsp, &runtime->block_list);
-                               list_del(&runtime->list);
-                               kfree(runtime);
-                       }
-
-                       /* now remove the module */
-                       block_list_remove(dsp, &module->block_list);
-                       list_del(&module->list);
-                       kfree(module);
-               }
-       }
-
-       /* remove all scratch blocks */
-       block_list_remove(dsp, &dsp->scratch_block_list);
-
-       mutex_unlock(&dsp->mutex);
-}
-EXPORT_SYMBOL_GPL(sst_fw_unload);
-
-/* free single firmware object */
-void sst_fw_free(struct sst_fw *sst_fw)
-{
-       struct sst_dsp *dsp = sst_fw->dsp;
-
-       mutex_lock(&dsp->mutex);
-       list_del(&sst_fw->list);
-       mutex_unlock(&dsp->mutex);
-
-       if (sst_fw->dma_buf)
-               dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,
-                       sst_fw->dmable_fw_paddr);
-       kfree(sst_fw);
-}
-EXPORT_SYMBOL_GPL(sst_fw_free);
-
-/* free all firmware objects */
-void sst_fw_free_all(struct sst_dsp *dsp)
-{
-       struct sst_fw *sst_fw, *t;
-
-       mutex_lock(&dsp->mutex);
-       list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
-
-               list_del(&sst_fw->list);
-               dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
-                       sst_fw->dmable_fw_paddr);
-               kfree(sst_fw);
-       }
-       mutex_unlock(&dsp->mutex);
-}
-EXPORT_SYMBOL_GPL(sst_fw_free_all);
-
-/* create a new SST generic module from FW template */
-struct sst_module *sst_module_new(struct sst_fw *sst_fw,
-       struct sst_module_template *template, void *private)
-{
-       struct sst_dsp *dsp = sst_fw->dsp;
-       struct sst_module *sst_module;
-
-       sst_module = kzalloc(sizeof(*sst_module), GFP_KERNEL);
-       if (sst_module == NULL)
-               return NULL;
-
-       sst_module->id = template->id;
-       sst_module->dsp = dsp;
-       sst_module->sst_fw = sst_fw;
-       sst_module->scratch_size = template->scratch_size;
-       sst_module->persistent_size = template->persistent_size;
-       sst_module->entry = template->entry;
-
-       INIT_LIST_HEAD(&sst_module->block_list);
-       INIT_LIST_HEAD(&sst_module->runtime_list);
-
-       mutex_lock(&dsp->mutex);
-       list_add(&sst_module->list, &dsp->module_list);
-       mutex_unlock(&dsp->mutex);
-
-       return sst_module;
-}
-EXPORT_SYMBOL_GPL(sst_module_new);
-
-/* free firmware module and remove from available list */
-void sst_module_free(struct sst_module *sst_module)
-{
-       struct sst_dsp *dsp = sst_module->dsp;
-
-       mutex_lock(&dsp->mutex);
-       list_del(&sst_module->list);
-       mutex_unlock(&dsp->mutex);
-
-       kfree(sst_module);
-}
-EXPORT_SYMBOL_GPL(sst_module_free);
-
-struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module,
-       int id, void *private)
-{
-       struct sst_dsp *dsp = module->dsp;
-       struct sst_module_runtime *runtime;
-
-       runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
-       if (runtime == NULL)
-               return NULL;
-
-       runtime->id = id;
-       runtime->dsp = dsp;
-       runtime->module = module;
-       INIT_LIST_HEAD(&runtime->block_list);
-
-       mutex_lock(&dsp->mutex);
-       list_add(&runtime->list, &module->runtime_list);
-       mutex_unlock(&dsp->mutex);
-
-       return runtime;
-}
-EXPORT_SYMBOL_GPL(sst_module_runtime_new);
-
-void sst_module_runtime_free(struct sst_module_runtime *runtime)
-{
-       struct sst_dsp *dsp = runtime->dsp;
-
-       mutex_lock(&dsp->mutex);
-       list_del(&runtime->list);
-       mutex_unlock(&dsp->mutex);
-
-       kfree(runtime);
-}
-EXPORT_SYMBOL_GPL(sst_module_runtime_free);
-
-static struct sst_mem_block *find_block(struct sst_dsp *dsp,
-       struct sst_block_allocator *ba)
-{
-       struct sst_mem_block *block;
-
-       list_for_each_entry(block, &dsp->free_block_list, list) {
-               if (block->type == ba->type && block->offset == ba->offset)
-                       return block;
-       }
-
-       return NULL;
-}
-
-/* Block allocator must be on block boundary */
-static int block_alloc_contiguous(struct sst_dsp *dsp,
-       struct sst_block_allocator *ba, struct list_head *block_list)
-{
-       struct list_head tmp = LIST_HEAD_INIT(tmp);
-       struct sst_mem_block *block;
-       u32 block_start = SST_HSW_BLOCK_ANY;
-       int size = ba->size, offset = ba->offset;
-
-       while (ba->size > 0) {
-
-               block = find_block(dsp, ba);
-               if (!block) {
-                       list_splice(&tmp, &dsp->free_block_list);
-
-                       ba->size = size;
-                       ba->offset = offset;
-                       return -ENOMEM;
-               }
-
-               list_move_tail(&block->list, &tmp);
-               ba->offset += block->size;
-               ba->size -= block->size;
-       }
-       ba->size = size;
-       ba->offset = offset;
-
-       list_for_each_entry(block, &tmp, list) {
-
-               if (block->offset < block_start)
-                       block_start = block->offset;
-
-               list_add(&block->module_list, block_list);
-
-               dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
-                       block->type, block->index, block->offset);
-       }
-
-       list_splice(&tmp, &dsp->used_block_list);
-       return 0;
-}
-
-/* allocate first free DSP blocks for data - callers hold locks */
-static int block_alloc(struct sst_dsp *dsp, struct sst_block_allocator *ba,
-       struct list_head *block_list)
-{
-       struct sst_mem_block *block, *tmp;
-       int ret = 0;
-
-       if (ba->size == 0)
-               return 0;
-
-       /* find first free whole blocks that can hold module */
-       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
-
-               /* ignore blocks with wrong type */
-               if (block->type != ba->type)
-                       continue;
-
-               if (ba->size > block->size)
-                       continue;
-
-               ba->offset = block->offset;
-               block->bytes_used = ba->size % block->size;
-               list_add(&block->module_list, block_list);
-               list_move(&block->list, &dsp->used_block_list);
-               dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
-                       block->type, block->index, block->offset);
-               return 0;
-       }
-
-       /* then find free multiple blocks that can hold module */
-       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
-
-               /* ignore blocks with wrong type */
-               if (block->type != ba->type)
-                       continue;
-
-               /* do we span > 1 blocks */
-               if (ba->size > block->size) {
-
-                       /* align ba to block boundary */
-                       ba->offset = block->offset;
-
-                       ret = block_alloc_contiguous(dsp, ba, block_list);
-                       if (ret == 0)
-                               return ret;
-
-               }
-       }
-
-       /* not enough free block space */
-       return -ENOMEM;
-}
-
-int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba,
-       struct list_head *block_list)
-{
-       int ret;
-
-       dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n",
-               ba->size, ba->offset, ba->type);
-
-       mutex_lock(&dsp->mutex);
-
-       ret = block_alloc(dsp, ba, block_list);
-       if (ret < 0) {
-               dev_err(dsp->dev, "error: can't alloc blocks %d\n", ret);
-               goto out;
-       }
-
-       /* prepare DSP blocks for module usage */
-       ret = block_list_prepare(dsp, block_list);
-       if (ret < 0)
-               dev_err(dsp->dev, "error: prepare failed\n");
-
-out:
-       mutex_unlock(&dsp->mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_alloc_blocks);
-
-int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list)
-{
-       mutex_lock(&dsp->mutex);
-       block_list_remove(dsp, block_list);
-       mutex_unlock(&dsp->mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_free_blocks);
-
-/* allocate memory blocks for static module addresses - callers hold locks */
-static int block_alloc_fixed(struct sst_dsp *dsp, struct sst_block_allocator *ba,
-       struct list_head *block_list)
-{
-       struct sst_mem_block *block, *tmp;
-       struct sst_block_allocator ba_tmp = *ba;
-       u32 end = ba->offset + ba->size, block_end;
-       int err;
-
-       /* only IRAM/DRAM blocks are managed */
-       if (ba->type != SST_MEM_IRAM && ba->type != SST_MEM_DRAM)
-               return 0;
-
-       /* are blocks already attached to this module */
-       list_for_each_entry_safe(block, tmp, block_list, module_list) {
-
-               /* ignore blocks with wrong type */
-               if (block->type != ba->type)
-                       continue;
-
-               block_end = block->offset + block->size;
-
-               /* find block that holds section */
-               if (ba->offset >= block->offset && end <= block_end)
-                       return 0;
-
-               /* does block span more than 1 section */
-               if (ba->offset >= block->offset && ba->offset < block_end) {
-
-                       /* align ba to block boundary */
-                       ba_tmp.size -= block_end - ba->offset;
-                       ba_tmp.offset = block_end;
-                       err = block_alloc_contiguous(dsp, &ba_tmp, block_list);
-                       if (err < 0)
-                               return -ENOMEM;
-
-                       /* module already owns blocks */
-                       return 0;
-               }
-       }
-
-       /* find first free blocks that can hold section in free list */
-       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
-               block_end = block->offset + block->size;
-
-               /* ignore blocks with wrong type */
-               if (block->type != ba->type)
-                       continue;
-
-               /* find block that holds section */
-               if (ba->offset >= block->offset && end <= block_end) {
-
-                       /* add block */
-                       list_move(&block->list, &dsp->used_block_list);
-                       list_add(&block->module_list, block_list);
-                       dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
-                               block->type, block->index, block->offset);
-                       return 0;
-               }
-
-               /* does block span more than 1 section */
-               if (ba->offset >= block->offset && ba->offset < block_end) {
-
-                       /* add block */
-                       list_move(&block->list, &dsp->used_block_list);
-                       list_add(&block->module_list, block_list);
-                       /* align ba to block boundary */
-                       ba_tmp.size -= block_end - ba->offset;
-                       ba_tmp.offset = block_end;
-
-                       err = block_alloc_contiguous(dsp, &ba_tmp, block_list);
-                       if (err < 0)
-                               return -ENOMEM;
-
-                       return 0;
-               }
-       }
-
-       return -ENOMEM;
-}
-
-/* Load fixed module data into DSP memory blocks */
-int sst_module_alloc_blocks(struct sst_module *module)
-{
-       struct sst_dsp *dsp = module->dsp;
-       struct sst_fw *sst_fw = module->sst_fw;
-       struct sst_block_allocator ba;
-       int ret;
-
-       memset(&ba, 0, sizeof(ba));
-       ba.size = module->size;
-       ba.type = module->type;
-       ba.offset = module->offset;
-
-       dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n",
-               ba.size, ba.offset, ba.type);
-
-       mutex_lock(&dsp->mutex);
-
-       /* alloc blocks that includes this section */
-       ret = block_alloc_fixed(dsp, &ba, &module->block_list);
-       if (ret < 0) {
-               dev_err(dsp->dev,
-                       "error: no free blocks for section at offset 0x%x size 0x%x\n",
-                       module->offset, module->size);
-               mutex_unlock(&dsp->mutex);
-               return -ENOMEM;
-       }
-
-       /* prepare DSP blocks for module copy */
-       ret = block_list_prepare(dsp, &module->block_list);
-       if (ret < 0) {
-               dev_err(dsp->dev, "error: fw module prepare failed\n");
-               goto err;
-       }
-
-       /* copy partial module data to blocks */
-       if (dsp->fw_use_dma) {
-               ret = sst_dsp_dma_copyto(dsp,
-                       dsp->addr.lpe_base + module->offset,
-                       sst_fw->dmable_fw_paddr + module->data_offset,
-                       module->size);
-               if (ret < 0) {
-                       dev_err(dsp->dev, "error: module copy failed\n");
-                       goto err;
-               }
-       } else
-               sst_memcpy32(dsp->addr.lpe + module->offset, module->data,
-                       module->size);
-
-       mutex_unlock(&dsp->mutex);
-       return ret;
-
-err:
-       block_list_remove(dsp, &module->block_list);
-       mutex_unlock(&dsp->mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_module_alloc_blocks);
-
-/* Unload entire module from DSP memory */
-int sst_module_free_blocks(struct sst_module *module)
-{
-       struct sst_dsp *dsp = module->dsp;
-
-       mutex_lock(&dsp->mutex);
-       block_list_remove(dsp, &module->block_list);
-       mutex_unlock(&dsp->mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_module_free_blocks);
-
-int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
-       int offset)
-{
-       struct sst_dsp *dsp = runtime->dsp;
-       struct sst_module *module = runtime->module;
-       struct sst_block_allocator ba;
-       int ret;
-
-       if (module->persistent_size == 0)
-               return 0;
-
-       memset(&ba, 0, sizeof(ba));
-       ba.size = module->persistent_size;
-       ba.type = SST_MEM_DRAM;
-
-       mutex_lock(&dsp->mutex);
-
-       /* do we need to allocate at a fixed address ? */
-       if (offset != 0) {
-
-               ba.offset = offset;
-
-               dev_dbg(dsp->dev, "persistent fixed block request 0x%x bytes type %d offset 0x%x\n",
-                       ba.size, ba.type, ba.offset);
-
-               /* alloc blocks that includes this section */
-               ret = block_alloc_fixed(dsp, &ba, &runtime->block_list);
-
-       } else {
-               dev_dbg(dsp->dev, "persistent block request 0x%x bytes type %d\n",
-                       ba.size, ba.type);
-
-               /* alloc blocks that includes this section */
-               ret = block_alloc(dsp, &ba, &runtime->block_list);
-       }
-       if (ret < 0) {
-               dev_err(dsp->dev,
-               "error: no free blocks for runtime module size 0x%x\n",
-                       module->persistent_size);
-               mutex_unlock(&dsp->mutex);
-               return -ENOMEM;
-       }
-       runtime->persistent_offset = ba.offset;
-
-       /* prepare DSP blocks for module copy */
-       ret = block_list_prepare(dsp, &runtime->block_list);
-       if (ret < 0) {
-               dev_err(dsp->dev, "error: runtime block prepare failed\n");
-               goto err;
-       }
-
-       mutex_unlock(&dsp->mutex);
-       return ret;
-
-err:
-       block_list_remove(dsp, &module->block_list);
-       mutex_unlock(&dsp->mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_module_runtime_alloc_blocks);
-
-int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime)
-{
-       struct sst_dsp *dsp = runtime->dsp;
-
-       mutex_lock(&dsp->mutex);
-       block_list_remove(dsp, &runtime->block_list);
-       mutex_unlock(&dsp->mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_module_runtime_free_blocks);
-
-int sst_module_runtime_save(struct sst_module_runtime *runtime,
-       struct sst_module_runtime_context *context)
-{
-       struct sst_dsp *dsp = runtime->dsp;
-       struct sst_module *module = runtime->module;
-       int ret = 0;
-
-       dev_dbg(dsp->dev, "saving runtime %d memory at 0x%x size 0x%x\n",
-               runtime->id, runtime->persistent_offset,
-               module->persistent_size);
-
-       context->buffer = dma_alloc_coherent(dsp->dma_dev,
-               module->persistent_size,
-               &context->dma_buffer, GFP_DMA | GFP_KERNEL);
-       if (!context->buffer) {
-               dev_err(dsp->dev, "error: DMA context alloc failed\n");
-               return -ENOMEM;
-       }
-
-       mutex_lock(&dsp->mutex);
-
-       if (dsp->fw_use_dma) {
-
-               ret = sst_dsp_dma_get_channel(dsp, 0);
-               if (ret < 0)
-                       goto err;
-
-               ret = sst_dsp_dma_copyfrom(dsp, context->dma_buffer,
-                       dsp->addr.lpe_base + runtime->persistent_offset,
-                       module->persistent_size);
-               sst_dsp_dma_put_channel(dsp);
-               if (ret < 0) {
-                       dev_err(dsp->dev, "error: context copy failed\n");
-                       goto err;
-               }
-       } else
-               sst_memcpy32(context->buffer, dsp->addr.lpe +
-                       runtime->persistent_offset,
-                       module->persistent_size);
-
-err:
-       mutex_unlock(&dsp->mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_module_runtime_save);
-
-int sst_module_runtime_restore(struct sst_module_runtime *runtime,
-       struct sst_module_runtime_context *context)
-{
-       struct sst_dsp *dsp = runtime->dsp;
-       struct sst_module *module = runtime->module;
-       int ret = 0;
-
-       dev_dbg(dsp->dev, "restoring runtime %d memory at 0x%x size 0x%x\n",
-               runtime->id, runtime->persistent_offset,
-               module->persistent_size);
-
-       mutex_lock(&dsp->mutex);
-
-       if (!context->buffer) {
-               dev_info(dsp->dev, "no context buffer need to restore!\n");
-               goto err;
-       }
-
-       if (dsp->fw_use_dma) {
-
-               ret = sst_dsp_dma_get_channel(dsp, 0);
-               if (ret < 0)
-                       goto err;
-
-               ret = sst_dsp_dma_copyto(dsp,
-                       dsp->addr.lpe_base + runtime->persistent_offset,
-                       context->dma_buffer, module->persistent_size);
-               sst_dsp_dma_put_channel(dsp);
-               if (ret < 0) {
-                       dev_err(dsp->dev, "error: module copy failed\n");
-                       goto err;
-               }
-       } else
-               sst_memcpy32(dsp->addr.lpe + runtime->persistent_offset,
-                       context->buffer, module->persistent_size);
-
-       dma_free_coherent(dsp->dma_dev, module->persistent_size,
-                               context->buffer, context->dma_buffer);
-       context->buffer = NULL;
-
-err:
-       mutex_unlock(&dsp->mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_module_runtime_restore);
-
-/* register a DSP memory block for use with FW based modules */
-struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
-       u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
-       void *private)
-{
-       struct sst_mem_block *block;
-
-       block = kzalloc(sizeof(*block), GFP_KERNEL);
-       if (block == NULL)
-               return NULL;
-
-       block->offset = offset;
-       block->size = size;
-       block->index = index;
-       block->type = type;
-       block->dsp = dsp;
-       block->private = private;
-       block->ops = ops;
-
-       mutex_lock(&dsp->mutex);
-       list_add(&block->list, &dsp->free_block_list);
-       mutex_unlock(&dsp->mutex);
-
-       return block;
-}
-EXPORT_SYMBOL_GPL(sst_mem_block_register);
-
-/* unregister all DSP memory blocks */
-void sst_mem_block_unregister_all(struct sst_dsp *dsp)
-{
-       struct sst_mem_block *block, *tmp;
-
-       mutex_lock(&dsp->mutex);
-
-       /* unregister used blocks */
-       list_for_each_entry_safe(block, tmp, &dsp->used_block_list, list) {
-               list_del(&block->list);
-               kfree(block);
-       }
-
-       /* unregister free blocks */
-       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
-               list_del(&block->list);
-               kfree(block);
-       }
-
-       mutex_unlock(&dsp->mutex);
-}
-EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all);
-
-/* allocate scratch buffer blocks */
-int sst_block_alloc_scratch(struct sst_dsp *dsp)
-{
-       struct sst_module *module;
-       struct sst_block_allocator ba;
-       int ret;
-
-       mutex_lock(&dsp->mutex);
-
-       /* calculate required scratch size */
-       dsp->scratch_size = 0;
-       list_for_each_entry(module, &dsp->module_list, list) {
-               dev_dbg(dsp->dev, "module %d scratch req 0x%x bytes\n",
-                       module->id, module->scratch_size);
-               if (dsp->scratch_size < module->scratch_size)
-                       dsp->scratch_size = module->scratch_size;
-       }
-
-       dev_dbg(dsp->dev, "scratch buffer required is 0x%x bytes\n",
-               dsp->scratch_size);
-
-       if (dsp->scratch_size == 0) {
-               dev_info(dsp->dev, "no modules need scratch buffer\n");
-               mutex_unlock(&dsp->mutex);
-               return 0;
-       }
-
-       /* allocate blocks for module scratch buffers */
-       dev_dbg(dsp->dev, "allocating scratch blocks\n");
-
-       ba.size = dsp->scratch_size;
-       ba.type = SST_MEM_DRAM;
-
-       /* do we need to allocate at fixed offset */
-       if (dsp->scratch_offset != 0) {
-
-               dev_dbg(dsp->dev, "block request 0x%x bytes type %d at 0x%x\n",
-                       ba.size, ba.type, ba.offset);
-
-               ba.offset = dsp->scratch_offset;
-
-               /* alloc blocks that includes this section */
-               ret = block_alloc_fixed(dsp, &ba, &dsp->scratch_block_list);
-
-       } else {
-               dev_dbg(dsp->dev, "block request 0x%x bytes type %d\n",
-                       ba.size, ba.type);
-
-               ba.offset = 0;
-               ret = block_alloc(dsp, &ba, &dsp->scratch_block_list);
-       }
-       if (ret < 0) {
-               dev_err(dsp->dev, "error: can't alloc scratch blocks\n");
-               mutex_unlock(&dsp->mutex);
-               return ret;
-       }
-
-       ret = block_list_prepare(dsp, &dsp->scratch_block_list);
-       if (ret < 0) {
-               dev_err(dsp->dev, "error: scratch block prepare failed\n");
-               mutex_unlock(&dsp->mutex);
-               return ret;
-       }
-
-       /* assign the same offset of scratch to each module */
-       dsp->scratch_offset = ba.offset;
-       mutex_unlock(&dsp->mutex);
-       return dsp->scratch_size;
-}
-EXPORT_SYMBOL_GPL(sst_block_alloc_scratch);
-
-/* free all scratch blocks */
-void sst_block_free_scratch(struct sst_dsp *dsp)
-{
-       mutex_lock(&dsp->mutex);
-       block_list_remove(dsp, &dsp->scratch_block_list);
-       mutex_unlock(&dsp->mutex);
-}
-EXPORT_SYMBOL_GPL(sst_block_free_scratch);
-
-/* get a module from it's unique ID */
-struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id)
-{
-       struct sst_module *module;
-
-       mutex_lock(&dsp->mutex);
-
-       list_for_each_entry(module, &dsp->module_list, list) {
-               if (module->id == id) {
-                       mutex_unlock(&dsp->mutex);
-                       return module;
-               }
-       }
-
-       mutex_unlock(&dsp->mutex);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(sst_module_get_from_id);
-
-struct sst_module_runtime *sst_module_runtime_get_from_id(
-       struct sst_module *module, u32 id)
-{
-       struct sst_module_runtime *runtime;
-       struct sst_dsp *dsp = module->dsp;
-
-       mutex_lock(&dsp->mutex);
-
-       list_for_each_entry(runtime, &module->runtime_list, list) {
-               if (runtime->id == id) {
-                       mutex_unlock(&dsp->mutex);
-                       return runtime;
-               }
-       }
-
-       mutex_unlock(&dsp->mutex);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(sst_module_runtime_get_from_id);
-
-/* returns block address in DSP address space */
-u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
-       enum sst_mem_type type)
-{
-       switch (type) {
-       case SST_MEM_IRAM:
-               return offset - dsp->addr.iram_offset +
-                       dsp->addr.dsp_iram_offset;
-       case SST_MEM_DRAM:
-               return offset - dsp->addr.dram_offset +
-                       dsp->addr.dsp_dram_offset;
-       default:
-               return 0;
-       }
-}
-EXPORT_SYMBOL_GPL(sst_dsp_get_offset);
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
deleted file mode 100644 (file)
index c42ffae..0000000
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * Intel Haswell SST DSP driver
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include <linux/export.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
-#include <linux/firmware.h>
-#include <linux/pm_runtime.h>
-
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-#include "sst-haswell-ipc.h"
-
-#include <trace/events/hswadsp.h>
-
-#define SST_HSW_FW_SIGNATURE_SIZE      4
-#define SST_HSW_FW_SIGN                        "$SST"
-#define SST_HSW_FW_LIB_SIGN            "$LIB"
-
-#define SST_WPT_SHIM_OFFSET    0xFB000
-#define SST_LP_SHIM_OFFSET     0xE7000
-#define SST_WPT_IRAM_OFFSET    0xA0000
-#define SST_LP_IRAM_OFFSET     0x80000
-#define SST_WPT_DSP_DRAM_OFFSET        0x400000
-#define SST_WPT_DSP_IRAM_OFFSET        0x00000
-#define SST_LPT_DSP_DRAM_OFFSET        0x400000
-#define SST_LPT_DSP_IRAM_OFFSET        0x00000
-
-#define SST_SHIM_PM_REG                0x84
-
-#define SST_HSW_IRAM   1
-#define SST_HSW_DRAM   2
-#define SST_HSW_REGS   3
-
-struct dma_block_info {
-       __le32 type;            /* IRAM/DRAM */
-       __le32 size;            /* Bytes */
-       __le32 ram_offset;      /* Offset in I/DRAM */
-       __le32 rsvd;            /* Reserved field */
-} __attribute__((packed));
-
-struct fw_module_info {
-       __le32 persistent_size;
-       __le32 scratch_size;
-} __attribute__((packed));
-
-struct fw_header {
-       unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* FW signature */
-       __le32 file_size;               /* size of fw minus this header */
-       __le32 modules;         /*  # of modules */
-       __le32 file_format;     /* version of header format */
-       __le32 reserved[4];
-} __attribute__((packed));
-
-struct fw_module_header {
-       unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* module signature */
-       __le32 mod_size;        /* size of module */
-       __le32 blocks;  /* # of blocks */
-       __le16 padding;
-       __le16 type;    /* codec type, pp lib */
-       __le32 entry_point;
-       struct fw_module_info info;
-} __attribute__((packed));
-
-static void hsw_free(struct sst_dsp *sst);
-
-static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
-       struct fw_module_header *module)
-{
-       struct dma_block_info *block;
-       struct sst_module *mod;
-       struct sst_module_template template;
-       int count, ret;
-       void __iomem *ram;
-
-       /* TODO: allowed module types need to be configurable */
-       if (module->type != SST_HSW_MODULE_BASE_FW
-               && module->type != SST_HSW_MODULE_PCM_SYSTEM
-               && module->type != SST_HSW_MODULE_PCM
-               && module->type != SST_HSW_MODULE_PCM_REFERENCE
-               && module->type != SST_HSW_MODULE_PCM_CAPTURE
-               && module->type != SST_HSW_MODULE_LPAL)
-               return 0;
-
-       dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n",
-               module->signature, module->mod_size,
-               module->blocks, module->type);
-       dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point);
-       dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n",
-               module->info.persistent_size, module->info.scratch_size);
-
-       memset(&template, 0, sizeof(template));
-       template.id = module->type;
-       template.entry = module->entry_point - 4;
-       template.persistent_size = module->info.persistent_size;
-       template.scratch_size = module->info.scratch_size;
-
-       mod = sst_module_new(fw, &template, NULL);
-       if (mod == NULL)
-               return -ENOMEM;
-
-       block = (void *)module + sizeof(*module);
-
-       for (count = 0; count < module->blocks; count++) {
-
-               if (block->size <= 0) {
-                       dev_err(dsp->dev,
-                               "error: block %d size invalid\n", count);
-                       sst_module_free(mod);
-                       return -EINVAL;
-               }
-
-               switch (block->type) {
-               case SST_HSW_IRAM:
-                       ram = dsp->addr.lpe;
-                       mod->offset =
-                               block->ram_offset + dsp->addr.iram_offset;
-                       mod->type = SST_MEM_IRAM;
-                       break;
-               case SST_HSW_DRAM:
-                       ram = dsp->addr.lpe;
-                       mod->offset = block->ram_offset;
-                       mod->type = SST_MEM_DRAM;
-                       break;
-               default:
-                       dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n",
-                               block->type, count);
-                       sst_module_free(mod);
-                       return -EINVAL;
-               }
-
-               mod->size = block->size;
-               mod->data = (void *)block + sizeof(*block);
-               mod->data_offset = mod->data - fw->dma_buf;
-
-               dev_dbg(dsp->dev, "module block %d type 0x%x "
-                       "size 0x%x ==> ram %p offset 0x%x\n",
-                       count, mod->type, block->size, ram,
-                       block->ram_offset);
-
-               ret = sst_module_alloc_blocks(mod);
-               if (ret < 0) {
-                       dev_err(dsp->dev, "error: could not allocate blocks for module %d\n",
-                               count);
-                       sst_module_free(mod);
-                       return ret;
-               }
-
-               block = (void *)block + sizeof(*block) + block->size;
-       }
-
-       return 0;
-}
-
-static int hsw_parse_fw_image(struct sst_fw *sst_fw)
-{
-       struct fw_header *header;
-       struct fw_module_header *module;
-       struct sst_dsp *dsp = sst_fw->dsp;
-       int ret, count;
-
-       /* Read the header information from the data pointer */
-       header = (struct fw_header *)sst_fw->dma_buf;
-
-       /* verify FW */
-       if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) ||
-               (sst_fw->size != header->file_size + sizeof(*header))) {
-               dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n");
-               return -EINVAL;
-       }
-
-       dev_dbg(dsp->dev, "header size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
-               header->file_size, header->modules,
-               header->file_format, sizeof(*header));
-
-       /* parse each module */
-       module = (void *)sst_fw->dma_buf + sizeof(*header);
-       for (count = 0; count < header->modules; count++) {
-
-               /* module */
-               ret = hsw_parse_module(dsp, sst_fw, module);
-               if (ret < 0) {
-                       dev_err(dsp->dev, "error: invalid module %d\n", count);
-                       return ret;
-               }
-               module = (void *)module + sizeof(*module) + module->mod_size;
-       }
-
-       /* allocate scratch mem regions */
-       sst_block_alloc_scratch(dsp);
-
-       return 0;
-}
-
-static irqreturn_t hsw_irq(int irq, void *context)
-{
-       struct sst_dsp *sst = (struct sst_dsp *) context;
-       u32 isr;
-       int ret = IRQ_NONE;
-
-       spin_lock(&sst->spinlock);
-
-       /* Interrupt arrived, check src */
-       isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
-       if (isr & SST_ISRX_DONE) {
-               trace_sst_irq_done(isr,
-                       sst_dsp_shim_read_unlocked(sst, SST_IMRX));
-
-               /* Mask Done interrupt before return */
-               sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
-                       SST_IMRX_DONE, SST_IMRX_DONE);
-               ret = IRQ_WAKE_THREAD;
-       }
-
-       if (isr & SST_ISRX_BUSY) {
-               trace_sst_irq_busy(isr,
-                       sst_dsp_shim_read_unlocked(sst, SST_IMRX));
-
-               /* Mask Busy interrupt before return */
-               sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
-                       SST_IMRX_BUSY, SST_IMRX_BUSY);
-               ret = IRQ_WAKE_THREAD;
-       }
-
-       spin_unlock(&sst->spinlock);
-       return ret;
-}
-
-static void hsw_set_dsp_D3(struct sst_dsp *sst)
-{
-       u32 val;
-       u32 reg;
-
-       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       /* enable power gating and switch off DRAM & IRAM blocks */
-       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
-       val |= SST_VDRTCL0_DSRAMPGE_MASK |
-               SST_VDRTCL0_ISRAMPGE_MASK;
-       val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD);
-       writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
-
-       /* switch off audio PLL */
-       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       val |= SST_VDRTCL2_APLLSE_MASK;
-       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       /* disable MCLK(clkctl.smos = 0) */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
-               SST_CLKCTL_MASK, 0);
-
-       /* Set D3 state, delay 50 us */
-       val = readl(sst->addr.pci_cfg + SST_PMCS);
-       val |= SST_PMCS_PS_MASK;
-       writel(val, sst->addr.pci_cfg + SST_PMCS);
-       udelay(50);
-
-       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       udelay(50);
-
-}
-
-static void hsw_reset(struct sst_dsp *sst)
-{
-       /* put DSP into reset and stall */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
-               SST_CSR_RST | SST_CSR_STALL,
-               SST_CSR_RST | SST_CSR_STALL);
-
-       /* keep in reset for 10ms */
-       mdelay(10);
-
-       /* take DSP out of reset and keep stalled for FW loading */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
-               SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
-}
-
-static int hsw_set_dsp_D0(struct sst_dsp *sst)
-{
-       int tries = 10;
-       u32 reg, fw_dump_bit;
-
-       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
-       reg |= SST_VDRTCL0_D3PGD;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
-
-       /* Set D0 state */
-       reg = readl(sst->addr.pci_cfg + SST_PMCS);
-       reg &= ~SST_PMCS_PS_MASK;
-       writel(reg, sst->addr.pci_cfg + SST_PMCS);
-
-       /* check that ADSP shim is enabled */
-       while (tries--) {
-               reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK;
-               if (reg == 0)
-                       goto finish;
-
-               msleep(1);
-       }
-
-       return -ENODEV;
-
-finish:
-       /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
-               SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
-
-       /* stall DSP core, set clk to 192/96Mhz */
-       sst_dsp_shim_update_bits_unlocked(sst,
-               SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK,
-               SST_CSR_STALL | SST_CSR_DCS(4));
-
-       /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
-               SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
-               SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
-
-       /* Stall and reset core, set CSR */
-       hsw_reset(sst);
-
-       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       udelay(50);
-
-       /* switch on audio PLL */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg &= ~SST_VDRTCL2_APLLSE_MASK;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       /* set default power gating control, enable power gating control for all blocks. that is,
-       can't be accessed, please enable each block before accessing. */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
-       reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
-       /* for D0, always enable the block(DSRAM[0]) used for FW dump */
-       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
-       writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
-
-
-       /* disable DMA finish function for SSP0 & SSP1 */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
-               SST_CSR2_SDFD_SSP1);
-
-       /* set on-demond mode on engine 0,1 for all channels */
-       sst_dsp_shim_update_bits(sst, SST_HMDC,
-                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
-                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH);
-
-       /* Enable Interrupt from both sides */
-       sst_dsp_shim_update_bits(sst, SST_IMRX, (SST_IMRX_BUSY | SST_IMRX_DONE),
-                                0x0);
-       sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY |
-                               SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0);
-
-       /* clear IPC registers */
-       sst_dsp_shim_write(sst, SST_IPCX, 0x0);
-       sst_dsp_shim_write(sst, SST_IPCD, 0x0);
-       sst_dsp_shim_write(sst, 0x80, 0x6);
-       sst_dsp_shim_write(sst, 0xe0, 0x300a);
-
-       return 0;
-}
-
-static void hsw_boot(struct sst_dsp *sst)
-{
-       /* set oportunistic mode on engine 0,1 for all channels */
-       sst_dsp_shim_update_bits(sst, SST_HMDC,
-                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, 0);
-
-       /* set DSP to RUN */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
-}
-
-static void hsw_stall(struct sst_dsp *sst)
-{
-       /* stall DSP */
-       sst_dsp_shim_update_bits(sst, SST_CSR,
-               SST_CSR_24MHZ_LPCS | SST_CSR_STALL,
-               SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
-}
-
-static void hsw_sleep(struct sst_dsp *sst)
-{
-       dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n");
-
-       /* put DSP into reset and stall */
-       sst_dsp_shim_update_bits(sst, SST_CSR,
-               SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL,
-               SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
-
-       hsw_set_dsp_D3(sst);
-       dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
-}
-
-static int hsw_wake(struct sst_dsp *sst)
-{
-       int ret;
-
-       dev_dbg(sst->dev, "HSW_PM dsp runtime resume\n");
-
-       ret = hsw_set_dsp_D0(sst);
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(sst->dev, "HSW_PM dsp runtime resume exit\n");
-
-       return 0;
-}
-
-struct sst_adsp_memregion {
-       u32 start;
-       u32 end;
-       int blocks;
-       enum sst_mem_type type;
-};
-
-/* lynx point ADSP mem regions */
-static const struct sst_adsp_memregion lp_region[] = {
-       {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
-       {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */
-       {0x80000, 0xE0000, 12, SST_MEM_IRAM}, /* I-SRAM - 12 * 32kB */
-};
-
-/* wild cat point ADSP mem regions */
-static const struct sst_adsp_memregion wpt_region[] = {
-       {0x00000, 0xA0000, 20, SST_MEM_DRAM}, /* D-SRAM0,D-SRAM1,D-SRAM2 - 20 * 32kB */
-       {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */
-};
-
-static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
-{
-       /* ADSP DRAM & IRAM */
-       sst->addr.lpe_base = pdata->lpe_base;
-       sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
-       if (!sst->addr.lpe)
-               return -ENODEV;
-
-       /* ADSP PCI MMIO config space */
-       sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
-       if (!sst->addr.pci_cfg) {
-               iounmap(sst->addr.lpe);
-               return -ENODEV;
-       }
-
-       /* SST Shim */
-       sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
-       return 0;
-}
-
-struct sst_sram_shift {
-       u32 dev_id;     /* SST Device IDs  */
-       u32 iram_shift;
-       u32 dram_shift;
-};
-
-static const struct sst_sram_shift sram_shift[] = {
-       {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */
-       {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */
-};
-
-static u32 hsw_block_get_bit(struct sst_mem_block *block)
-{
-       u32 bit = 0, shift = 0, index;
-       struct sst_dsp *sst = block->dsp;
-
-       for (index = 0; index < ARRAY_SIZE(sram_shift); index++) {
-               if (sram_shift[index].dev_id == sst->id)
-                       break;
-       }
-
-       if (index < ARRAY_SIZE(sram_shift)) {
-               switch (block->type) {
-               case SST_MEM_DRAM:
-                       shift = sram_shift[index].dram_shift;
-                       break;
-               case SST_MEM_IRAM:
-                       shift = sram_shift[index].iram_shift;
-                       break;
-               default:
-                       shift = 0;
-               }
-       } else
-               shift = 0;
-
-       bit = 1 << (block->index + shift);
-
-       return bit;
-}
-
-/*dummy read a SRAM block.*/
-static void sst_mem_block_dummy_read(struct sst_mem_block *block)
-{
-       u32 size;
-       u8 tmp_buf[4];
-       struct sst_dsp *sst = block->dsp;
-
-       size = block->size > 4 ? 4 : block->size;
-       memcpy_fromio(tmp_buf, sst->addr.lpe + block->offset, size);
-}
-
-/* enable 32kB memory block - locks held by caller */
-static int hsw_block_enable(struct sst_mem_block *block)
-{
-       struct sst_dsp *sst = block->dsp;
-       u32 bit, val;
-
-       if (block->users++ > 0)
-               return 0;
-
-       dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n",
-               block->type, block->index, block->offset);
-
-       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
-       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       val &= ~SST_VDRTCL2_DCLCGE;
-       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
-       bit = hsw_block_get_bit(block);
-       writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0);
-
-       /* wait 18 DSP clock ticks */
-       udelay(10);
-
-       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
-       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       val |= SST_VDRTCL2_DCLCGE;
-       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       udelay(50);
-
-       /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/
-       sst_mem_block_dummy_read(block);
-       return 0;
-}
-
-/* disable 32kB memory block - locks held by caller */
-static int hsw_block_disable(struct sst_mem_block *block)
-{
-       struct sst_dsp *sst = block->dsp;
-       u32 bit, val;
-
-       if (--block->users > 0)
-               return 0;
-
-       dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n",
-               block->type, block->index, block->offset);
-
-       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
-       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       val &= ~SST_VDRTCL2_DCLCGE;
-       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-
-       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
-       bit = hsw_block_get_bit(block);
-       /* don't disable DSRAM[0], keep it always enable for FW dump*/
-       if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT))
-               writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
-
-       /* wait 18 DSP clock ticks */
-       udelay(10);
-
-       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
-       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       val |= SST_VDRTCL2_DCLCGE;
-       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
-
-       udelay(50);
-
-       return 0;
-}
-
-static struct sst_block_ops sst_hsw_ops = {
-       .enable = hsw_block_enable,
-       .disable = hsw_block_disable,
-};
-
-static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
-{
-       const struct sst_adsp_memregion *region;
-       struct device *dev;
-       int ret = -ENODEV, i, j, region_count;
-       u32 offset, size, fw_dump_bit;
-
-       dev = sst->dma_dev;
-
-       switch (sst->id) {
-       case SST_DEV_ID_LYNX_POINT:
-               region = lp_region;
-               region_count = ARRAY_SIZE(lp_region);
-               sst->addr.iram_offset = SST_LP_IRAM_OFFSET;
-               sst->addr.dsp_iram_offset = SST_LPT_DSP_IRAM_OFFSET;
-               sst->addr.dsp_dram_offset = SST_LPT_DSP_DRAM_OFFSET;
-               sst->addr.shim_offset = SST_LP_SHIM_OFFSET;
-               break;
-       case SST_DEV_ID_WILDCAT_POINT:
-               region = wpt_region;
-               region_count = ARRAY_SIZE(wpt_region);
-               sst->addr.iram_offset = SST_WPT_IRAM_OFFSET;
-               sst->addr.dsp_iram_offset = SST_WPT_DSP_IRAM_OFFSET;
-               sst->addr.dsp_dram_offset = SST_WPT_DSP_DRAM_OFFSET;
-               sst->addr.shim_offset = SST_WPT_SHIM_OFFSET;
-               break;
-       default:
-               dev_err(dev, "error: failed to get mem resources\n");
-               return ret;
-       }
-
-       ret = hsw_acpi_resource_map(sst, pdata);
-       if (ret < 0) {
-               dev_err(dev, "error: failed to map resources\n");
-               return ret;
-       }
-
-       /* enable the DSP SHIM */
-       ret = hsw_set_dsp_D0(sst);
-       if (ret < 0) {
-               dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
-               return ret;
-       }
-
-       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
-       if (ret)
-               return ret;
-
-
-       /* register DSP memory blocks - ideally we should get this from ACPI */
-       for (i = 0; i < region_count; i++) {
-               offset = region[i].start;
-               size = (region[i].end - region[i].start) / region[i].blocks;
-
-               /* register individual memory blocks */
-               for (j = 0; j < region[i].blocks; j++) {
-                       sst_mem_block_register(sst, offset, size,
-                               region[i].type, &sst_hsw_ops, j, sst);
-                       offset += size;
-               }
-       }
-
-       /* always enable the block(DSRAM[0]) used for FW dump */
-       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
-       /* set default power gating control, enable power gating control for all blocks. that is,
-       can't be accessed, please enable each block before accessing. */
-       writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
-
-       return 0;
-}
-
-static void hsw_free(struct sst_dsp *sst)
-{
-       sst_mem_block_unregister_all(sst);
-       iounmap(sst->addr.lpe);
-       iounmap(sst->addr.pci_cfg);
-}
-
-struct sst_ops haswell_ops = {
-       .reset = hsw_reset,
-       .boot = hsw_boot,
-       .stall = hsw_stall,
-       .wake = hsw_wake,
-       .sleep = hsw_sleep,
-       .write = sst_shim32_write,
-       .read = sst_shim32_read,
-       .write64 = sst_shim32_write64,
-       .read64 = sst_shim32_read64,
-       .ram_read = sst_memcpy_fromio_32,
-       .ram_write = sst_memcpy_toio_32,
-       .irq_handler = hsw_irq,
-       .init = hsw_init,
-       .free = hsw_free,
-       .parse_fw = hsw_parse_fw_image,
-};
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
deleted file mode 100644 (file)
index 394af56..0000000
+++ /dev/null
@@ -1,2000 +0,0 @@
-/*
- *  Intel SST Haswell/Broadwell IPC Support
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/platform_device.h>
-#include <linux/kthread.h>
-#include <linux/firmware.h>
-#include <linux/dma-mapping.h>
-#include <linux/debugfs.h>
-#include <linux/pm_runtime.h>
-#include <sound/asound.h>
-
-#include "sst-haswell-ipc.h"
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-
-/* Global Message - Generic */
-#define IPC_GLB_TYPE_SHIFT     24
-#define IPC_GLB_TYPE_MASK      (0x1f << IPC_GLB_TYPE_SHIFT)
-#define IPC_GLB_TYPE(x)                (x << IPC_GLB_TYPE_SHIFT)
-
-/* Global Message - Reply */
-#define IPC_GLB_REPLY_SHIFT    0
-#define IPC_GLB_REPLY_MASK     (0x1f << IPC_GLB_REPLY_SHIFT)
-#define IPC_GLB_REPLY_TYPE(x)  (x << IPC_GLB_REPLY_TYPE_SHIFT)
-
-/* Stream Message - Generic */
-#define IPC_STR_TYPE_SHIFT     20
-#define IPC_STR_TYPE_MASK      (0xf << IPC_STR_TYPE_SHIFT)
-#define IPC_STR_TYPE(x)                (x << IPC_STR_TYPE_SHIFT)
-#define IPC_STR_ID_SHIFT       16
-#define IPC_STR_ID_MASK                (0xf << IPC_STR_ID_SHIFT)
-#define IPC_STR_ID(x)          (x << IPC_STR_ID_SHIFT)
-
-/* Stream Message - Reply */
-#define IPC_STR_REPLY_SHIFT    0
-#define IPC_STR_REPLY_MASK     (0x1f << IPC_STR_REPLY_SHIFT)
-
-/* Stream Stage Message - Generic */
-#define IPC_STG_TYPE_SHIFT     12
-#define IPC_STG_TYPE_MASK      (0xf << IPC_STG_TYPE_SHIFT)
-#define IPC_STG_TYPE(x)                (x << IPC_STG_TYPE_SHIFT)
-#define IPC_STG_ID_SHIFT       10
-#define IPC_STG_ID_MASK                (0x3 << IPC_STG_ID_SHIFT)
-#define IPC_STG_ID(x)          (x << IPC_STG_ID_SHIFT)
-
-/* Stream Stage Message - Reply */
-#define IPC_STG_REPLY_SHIFT    0
-#define IPC_STG_REPLY_MASK     (0x1f << IPC_STG_REPLY_SHIFT)
-
-/* Debug Log Message - Generic */
-#define IPC_LOG_OP_SHIFT       20
-#define IPC_LOG_OP_MASK                (0xf << IPC_LOG_OP_SHIFT)
-#define IPC_LOG_OP_TYPE(x)     (x << IPC_LOG_OP_SHIFT)
-#define IPC_LOG_ID_SHIFT       16
-#define IPC_LOG_ID_MASK                (0xf << IPC_LOG_ID_SHIFT)
-#define IPC_LOG_ID(x)          (x << IPC_LOG_ID_SHIFT)
-
-/* IPC message timeout (msecs) */
-#define IPC_TIMEOUT_MSECS      300
-#define IPC_BOOT_MSECS         200
-#define IPC_MSG_WAIT           0
-#define IPC_MSG_NOWAIT         1
-
-/* Firmware Ready Message */
-#define IPC_FW_READY           (0x1 << 29)
-#define IPC_STATUS_MASK                (0x3 << 30)
-
-#define IPC_EMPTY_LIST_SIZE    8
-#define IPC_MAX_STREAMS                4
-
-/* Mailbox */
-#define IPC_MAX_MAILBOX_BYTES  256
-
-#define INVALID_STREAM_HW_ID   0xffffffff
-
-/* Global Message - Types and Replies */
-enum ipc_glb_type {
-       IPC_GLB_GET_FW_VERSION = 0,             /* Retrieves firmware version */
-       IPC_GLB_PERFORMANCE_MONITOR = 1,        /* Performance monitoring actions */
-       IPC_GLB_ALLOCATE_STREAM = 3,            /* Request to allocate new stream */
-       IPC_GLB_FREE_STREAM = 4,                /* Request to free stream */
-       IPC_GLB_GET_FW_CAPABILITIES = 5,        /* Retrieves firmware capabilities */
-       IPC_GLB_STREAM_MESSAGE = 6,             /* Message directed to stream or its stages */
-       /* Request to store firmware context during D0->D3 transition */
-       IPC_GLB_REQUEST_DUMP = 7,
-       /* Request to restore firmware context during D3->D0 transition */
-       IPC_GLB_RESTORE_CONTEXT = 8,
-       IPC_GLB_GET_DEVICE_FORMATS = 9,         /* Set device format */
-       IPC_GLB_SET_DEVICE_FORMATS = 10,        /* Get device format */
-       IPC_GLB_SHORT_REPLY = 11,
-       IPC_GLB_ENTER_DX_STATE = 12,
-       IPC_GLB_GET_MIXER_STREAM_INFO = 13,     /* Request mixer stream params */
-       IPC_GLB_DEBUG_LOG_MESSAGE = 14,         /* Message to or from the debug logger. */
-       IPC_GLB_REQUEST_TRANSFER = 16,          /* < Request Transfer for host */
-       IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17,      /* Maximum message number */
-};
-
-enum ipc_glb_reply {
-       IPC_GLB_REPLY_SUCCESS = 0,              /* The operation was successful. */
-       IPC_GLB_REPLY_ERROR_INVALID_PARAM = 1,  /* Invalid parameter was passed. */
-       IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE = 2, /* Uknown message type was resceived. */
-       IPC_GLB_REPLY_OUT_OF_RESOURCES = 3,     /* No resources to satisfy the request. */
-       IPC_GLB_REPLY_BUSY = 4,                 /* The system or resource is busy. */
-       IPC_GLB_REPLY_PENDING = 5,              /* The action was scheduled for processing.  */
-       IPC_GLB_REPLY_FAILURE = 6,              /* Critical error happened. */
-       IPC_GLB_REPLY_INVALID_REQUEST = 7,      /* Request can not be completed. */
-       IPC_GLB_REPLY_STAGE_UNINITIALIZED = 8,  /* Processing stage was uninitialized. */
-       IPC_GLB_REPLY_NOT_FOUND = 9,            /* Required resource can not be found. */
-       IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10,  /* Source was not started. */
-};
-
-/* Stream Message - Types */
-enum ipc_str_operation {
-       IPC_STR_RESET = 0,
-       IPC_STR_PAUSE = 1,
-       IPC_STR_RESUME = 2,
-       IPC_STR_STAGE_MESSAGE = 3,
-       IPC_STR_NOTIFICATION = 4,
-       IPC_STR_MAX_MESSAGE
-};
-
-/* Stream Stage Message Types */
-enum ipc_stg_operation {
-       IPC_STG_GET_VOLUME = 0,
-       IPC_STG_SET_VOLUME,
-       IPC_STG_SET_WRITE_POSITION,
-       IPC_STG_SET_FX_ENABLE,
-       IPC_STG_SET_FX_DISABLE,
-       IPC_STG_SET_FX_GET_PARAM,
-       IPC_STG_SET_FX_SET_PARAM,
-       IPC_STG_SET_FX_GET_INFO,
-       IPC_STG_MUTE_LOOPBACK,
-       IPC_STG_MAX_MESSAGE
-};
-
-/* Stream Stage Message Types For Notification*/
-enum ipc_stg_operation_notify {
-       IPC_POSITION_CHANGED = 0,
-       IPC_STG_GLITCH,
-       IPC_STG_MAX_NOTIFY
-};
-
-enum ipc_glitch_type {
-       IPC_GLITCH_UNDERRUN = 1,
-       IPC_GLITCH_DECODER_ERROR,
-       IPC_GLITCH_DOUBLED_WRITE_POS,
-       IPC_GLITCH_MAX
-};
-
-/* Debug Control */
-enum ipc_debug_operation {
-       IPC_DEBUG_ENABLE_LOG = 0,
-       IPC_DEBUG_DISABLE_LOG = 1,
-       IPC_DEBUG_REQUEST_LOG_DUMP = 2,
-       IPC_DEBUG_NOTIFY_LOG_DUMP = 3,
-       IPC_DEBUG_MAX_DEBUG_LOG
-};
-
-/* Firmware Ready */
-struct sst_hsw_ipc_fw_ready {
-       u32 inbox_offset;
-       u32 outbox_offset;
-       u32 inbox_size;
-       u32 outbox_size;
-       u32 fw_info_size;
-       u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)];
-} __attribute__((packed));
-
-struct ipc_message {
-       struct list_head list;
-       u32 header;
-
-       /* direction wrt host CPU */
-       char tx_data[IPC_MAX_MAILBOX_BYTES];
-       size_t tx_size;
-       char rx_data[IPC_MAX_MAILBOX_BYTES];
-       size_t rx_size;
-
-       wait_queue_head_t waitq;
-       bool pending;
-       bool complete;
-       bool wait;
-       int errno;
-};
-
-struct sst_hsw_stream;
-struct sst_hsw;
-
-/* Stream infomation */
-struct sst_hsw_stream {
-       /* configuration */
-       struct sst_hsw_ipc_stream_alloc_req request;
-       struct sst_hsw_ipc_stream_alloc_reply reply;
-       struct sst_hsw_ipc_stream_free_req free_req;
-
-       /* Mixer info */
-       u32 mute_volume[SST_HSW_NO_CHANNELS];
-       u32 mute[SST_HSW_NO_CHANNELS];
-
-       /* runtime info */
-       struct sst_hsw *hsw;
-       int host_id;
-       bool commited;
-       bool running;
-
-       /* Notification work */
-       struct work_struct notify_work;
-       u32 header;
-
-       /* Position info from DSP */
-       struct sst_hsw_ipc_stream_set_position wpos;
-       struct sst_hsw_ipc_stream_get_position rpos;
-       struct sst_hsw_ipc_stream_glitch_position glitch;
-
-       /* Volume info */
-       struct sst_hsw_ipc_volume_req vol_req;
-
-       /* driver callback */
-       u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
-       void *pdata;
-
-       /* record the fw read position when playback */
-       snd_pcm_uframes_t old_position;
-       bool play_silence;
-       struct list_head node;
-};
-
-/* FW log ring information */
-struct sst_hsw_log_stream {
-       dma_addr_t dma_addr;
-       unsigned char *dma_area;
-       unsigned char *ring_descr;
-       int pages;
-       int size;
-
-       /* Notification work */
-       struct work_struct notify_work;
-       wait_queue_head_t readers_wait_q;
-       struct mutex rw_mutex;
-
-       u32 last_pos;
-       u32 curr_pos;
-       u32 reader_pos;
-
-       /* fw log config */
-       u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
-
-       struct sst_hsw *hsw;
-};
-
-/* SST Haswell IPC data */
-struct sst_hsw {
-       struct device *dev;
-       struct sst_dsp *dsp;
-       struct platform_device *pdev_pcm;
-
-       /* FW config */
-       struct sst_hsw_ipc_fw_ready fw_ready;
-       struct sst_hsw_ipc_fw_version version;
-       bool fw_done;
-       struct sst_fw *sst_fw;
-
-       /* stream */
-       struct list_head stream_list;
-
-       /* global mixer */
-       struct sst_hsw_ipc_stream_info_reply mixer_info;
-       enum sst_hsw_volume_curve curve_type;
-       u32 curve_duration;
-       u32 mute[SST_HSW_NO_CHANNELS];
-       u32 mute_volume[SST_HSW_NO_CHANNELS];
-
-       /* DX */
-       struct sst_hsw_ipc_dx_reply dx;
-       void *dx_context;
-       dma_addr_t dx_context_paddr;
-
-       /* boot */
-       wait_queue_head_t boot_wait;
-       bool boot_complete;
-       bool shutdown;
-
-       /* IPC messaging */
-       struct list_head tx_list;
-       struct list_head rx_list;
-       struct list_head empty_list;
-       wait_queue_head_t wait_txq;
-       struct task_struct *tx_thread;
-       struct kthread_worker kworker;
-       struct kthread_work kwork;
-       bool pending;
-       struct ipc_message *msg;
-
-       /* FW log stream */
-       struct sst_hsw_log_stream log_stream;
-};
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/hswadsp.h>
-
-static inline u32 msg_get_global_type(u32 msg)
-{
-       return (msg & IPC_GLB_TYPE_MASK) >> IPC_GLB_TYPE_SHIFT;
-}
-
-static inline u32 msg_get_global_reply(u32 msg)
-{
-       return (msg & IPC_GLB_REPLY_MASK) >> IPC_GLB_REPLY_SHIFT;
-}
-
-static inline u32 msg_get_stream_type(u32 msg)
-{
-       return (msg & IPC_STR_TYPE_MASK) >>  IPC_STR_TYPE_SHIFT;
-}
-
-static inline u32 msg_get_stage_type(u32 msg)
-{
-       return (msg & IPC_STG_TYPE_MASK) >>  IPC_STG_TYPE_SHIFT;
-}
-
-static inline u32 msg_get_stream_id(u32 msg)
-{
-       return (msg & IPC_STR_ID_MASK) >>  IPC_STR_ID_SHIFT;
-}
-
-static inline u32 msg_get_notify_reason(u32 msg)
-{
-       return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
-}
-
-u32 create_channel_map(enum sst_hsw_channel_config config)
-{
-       switch (config) {
-       case SST_HSW_CHANNEL_CONFIG_MONO:
-               return (0xFFFFFFF0 | SST_HSW_CHANNEL_CENTER);
-       case SST_HSW_CHANNEL_CONFIG_STEREO:
-               return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
-                       | (SST_HSW_CHANNEL_RIGHT << 4));
-       case SST_HSW_CHANNEL_CONFIG_2_POINT_1:
-               return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
-                       | (SST_HSW_CHANNEL_RIGHT << 4)
-                       | (SST_HSW_CHANNEL_LFE << 8 ));
-       case SST_HSW_CHANNEL_CONFIG_3_POINT_0:
-               return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
-                       | (SST_HSW_CHANNEL_CENTER << 4)
-                       | (SST_HSW_CHANNEL_RIGHT << 8));
-       case SST_HSW_CHANNEL_CONFIG_3_POINT_1:
-               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
-                       | (SST_HSW_CHANNEL_CENTER << 4)
-                       | (SST_HSW_CHANNEL_RIGHT << 8)
-                       | (SST_HSW_CHANNEL_LFE << 12));
-       case SST_HSW_CHANNEL_CONFIG_QUATRO:
-               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
-                       | (SST_HSW_CHANNEL_RIGHT << 4)
-                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 8)
-                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 12));
-       case SST_HSW_CHANNEL_CONFIG_4_POINT_0:
-               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
-                       | (SST_HSW_CHANNEL_CENTER << 4)
-                       | (SST_HSW_CHANNEL_RIGHT << 8)
-                       | (SST_HSW_CHANNEL_CENTER_SURROUND << 12));
-       case SST_HSW_CHANNEL_CONFIG_5_POINT_0:
-               return (0xFFF00000 | SST_HSW_CHANNEL_LEFT
-                       | (SST_HSW_CHANNEL_CENTER << 4)
-                       | (SST_HSW_CHANNEL_RIGHT << 8)
-                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
-                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16));
-       case SST_HSW_CHANNEL_CONFIG_5_POINT_1:
-               return (0xFF000000 | SST_HSW_CHANNEL_CENTER
-                       | (SST_HSW_CHANNEL_LEFT << 4)
-                       | (SST_HSW_CHANNEL_RIGHT << 8)
-                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
-                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16)
-                       | (SST_HSW_CHANNEL_LFE << 20));
-       case SST_HSW_CHANNEL_CONFIG_DUAL_MONO:
-               return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
-                       | (SST_HSW_CHANNEL_LEFT << 4));
-       default:
-               return 0xFFFFFFFF;
-       }
-}
-
-static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw,
-       int stream_id)
-{
-       struct sst_hsw_stream *stream;
-
-       list_for_each_entry(stream, &hsw->stream_list, node) {
-               if (stream->reply.stream_hw_id == stream_id)
-                       return stream;
-       }
-
-       return NULL;
-}
-
-static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text)
-{
-       struct sst_dsp *sst = hsw->dsp;
-       u32 isr, ipcd, imrx, ipcx;
-
-       ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX);
-       isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
-       ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
-       imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX);
-
-       dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n",
-               text, ipcx, isr, ipcd, imrx);
-}
-
-/* locks held by caller */
-static struct ipc_message *msg_get_empty(struct sst_hsw *hsw)
-{
-       struct ipc_message *msg = NULL;
-
-       if (!list_empty(&hsw->empty_list)) {
-               msg = list_first_entry(&hsw->empty_list, struct ipc_message,
-                       list);
-               list_del(&msg->list);
-       }
-
-       return msg;
-}
-
-static void ipc_tx_msgs(struct kthread_work *work)
-{
-       struct sst_hsw *hsw =
-               container_of(work, struct sst_hsw, kwork);
-       struct ipc_message *msg;
-       unsigned long flags;
-       u32 ipcx;
-
-       spin_lock_irqsave(&hsw->dsp->spinlock, flags);
-
-       if (list_empty(&hsw->tx_list) || hsw->pending) {
-               spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
-               return;
-       }
-
-       /* if the DSP is busy, we will TX messages after IRQ.
-        * also postpone if we are in the middle of procesing completion irq*/
-       ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX);
-       if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) {
-               spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
-               return;
-       }
-
-       msg = list_first_entry(&hsw->tx_list, struct ipc_message, list);
-
-       list_move(&msg->list, &hsw->rx_list);
-
-       /* send the message */
-       sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size);
-       sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY);
-
-       spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
-}
-
-/* locks held by caller */
-static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg)
-{
-       msg->complete = true;
-       trace_ipc_reply("completed", msg->header);
-
-       if (!msg->wait)
-               list_add_tail(&msg->list, &hsw->empty_list);
-       else
-               wake_up(&msg->waitq);
-}
-
-static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg,
-       void *rx_data)
-{
-       unsigned long flags;
-       int ret;
-
-       /* wait for DSP completion (in all cases atm inc pending) */
-       ret = wait_event_timeout(msg->waitq, msg->complete,
-               msecs_to_jiffies(IPC_TIMEOUT_MSECS));
-
-       spin_lock_irqsave(&hsw->dsp->spinlock, flags);
-       if (ret == 0) {
-               ipc_shim_dbg(hsw, "message timeout");
-
-               trace_ipc_error("error message timeout for", msg->header);
-               list_del(&msg->list);
-               ret = -ETIMEDOUT;
-       } else {
-
-               /* copy the data returned from DSP */
-               if (msg->rx_size)
-                       memcpy(rx_data, msg->rx_data, msg->rx_size);
-               ret = msg->errno;
-       }
-
-       list_add_tail(&msg->list, &hsw->empty_list);
-       spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
-       return ret;
-}
-
-static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data,
-       size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait)
-{
-       struct ipc_message *msg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hsw->dsp->spinlock, flags);
-
-       msg = msg_get_empty(hsw);
-       if (msg == NULL) {
-               spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
-               return -EBUSY;
-       }
-
-       if (tx_bytes)
-               memcpy(msg->tx_data, tx_data, tx_bytes);
-
-       msg->header = header;
-       msg->tx_size = tx_bytes;
-       msg->rx_size = rx_bytes;
-       msg->wait = wait;
-       msg->errno = 0;
-       msg->pending = false;
-       msg->complete = false;
-
-       list_add_tail(&msg->list, &hsw->tx_list);
-       spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
-
-       queue_kthread_work(&hsw->kworker, &hsw->kwork);
-
-       if (wait)
-               return tx_wait_done(hsw, msg, rx_data);
-       else
-               return 0;
-}
-
-static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header,
-       void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
-{
-       return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data,
-               rx_bytes, 1);
-}
-
-static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header,
-       void *tx_data, size_t tx_bytes)
-{
-       return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0);
-}
-
-static void hsw_fw_ready(struct sst_hsw *hsw, u32 header)
-{
-       struct sst_hsw_ipc_fw_ready fw_ready;
-       u32 offset;
-       u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)];
-       char *tmp[5], *pinfo;
-       int i = 0;
-
-       offset = (header & 0x1FFFFFFF) << 3;
-
-       dev_dbg(hsw->dev, "ipc: DSP is ready 0x%8.8x offset %d\n",
-               header, offset);
-
-       /* copy data from the DSP FW ready offset */
-       sst_dsp_read(hsw->dsp, &fw_ready, offset, sizeof(fw_ready));
-
-       sst_dsp_mailbox_init(hsw->dsp, fw_ready.inbox_offset,
-               fw_ready.inbox_size, fw_ready.outbox_offset,
-               fw_ready.outbox_size);
-
-       hsw->boot_complete = true;
-       wake_up(&hsw->boot_wait);
-
-       dev_dbg(hsw->dev, " mailbox upstream 0x%x - size 0x%x\n",
-               fw_ready.inbox_offset, fw_ready.inbox_size);
-       dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n",
-               fw_ready.outbox_offset, fw_ready.outbox_size);
-       if (fw_ready.fw_info_size < sizeof(fw_ready.fw_info)) {
-               fw_ready.fw_info[fw_ready.fw_info_size] = 0;
-               dev_dbg(hsw->dev, " Firmware info: %s \n", fw_ready.fw_info);
-
-               /* log the FW version info got from the mailbox here. */
-               memcpy(fw_info, fw_ready.fw_info, fw_ready.fw_info_size);
-               pinfo = &fw_info[0];
-               for (i = 0; i < sizeof(tmp) / sizeof(char *); i++)
-                       tmp[i] = strsep(&pinfo, " ");
-               dev_info(hsw->dev, "FW loaded, mailbox readback FW info: type %s, - "
-                       "version: %s.%s, build %s, source commit id: %s\n",
-                       tmp[0], tmp[1], tmp[2], tmp[3], tmp[4]);
-       }
-}
-
-static void hsw_notification_work(struct work_struct *work)
-{
-       struct sst_hsw_stream *stream = container_of(work,
-                       struct sst_hsw_stream, notify_work);
-       struct sst_hsw_ipc_stream_glitch_position *glitch = &stream->glitch;
-       struct sst_hsw_ipc_stream_get_position *pos = &stream->rpos;
-       struct sst_hsw *hsw = stream->hsw;
-       u32 reason;
-
-       reason = msg_get_notify_reason(stream->header);
-
-       switch (reason) {
-       case IPC_STG_GLITCH:
-               trace_ipc_notification("DSP stream under/overrun",
-                       stream->reply.stream_hw_id);
-               sst_dsp_inbox_read(hsw->dsp, glitch, sizeof(*glitch));
-
-               dev_err(hsw->dev, "glitch %d pos 0x%x write pos 0x%x\n",
-                       glitch->glitch_type, glitch->present_pos,
-                       glitch->write_pos);
-               break;
-
-       case IPC_POSITION_CHANGED:
-               trace_ipc_notification("DSP stream position changed for",
-                       stream->reply.stream_hw_id);
-               sst_dsp_inbox_read(hsw->dsp, pos, sizeof(*pos));
-
-               if (stream->notify_position)
-                       stream->notify_position(stream, stream->pdata);
-
-               break;
-       default:
-               dev_err(hsw->dev, "error: unknown notification 0x%x\n",
-                       stream->header);
-               break;
-       }
-
-       /* tell DSP that notification has been handled */
-       sst_dsp_shim_update_bits(hsw->dsp, SST_IPCD,
-               SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
-
-       /* unmask busy interrupt */
-       sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
-}
-
-static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header)
-{
-       struct ipc_message *msg;
-
-       /* clear reply bits & status bits */
-       header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
-
-       if (list_empty(&hsw->rx_list)) {
-               dev_err(hsw->dev, "error: rx list empty but received 0x%x\n",
-                       header);
-               return NULL;
-       }
-
-       list_for_each_entry(msg, &hsw->rx_list, list) {
-               if (msg->header == header)
-                       return msg;
-       }
-
-       return NULL;
-}
-
-static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg)
-{
-       struct sst_hsw_stream *stream;
-       u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
-       u32 stream_id = msg_get_stream_id(header);
-       u32 stream_msg = msg_get_stream_type(header);
-
-       stream = get_stream_by_id(hsw, stream_id);
-       if (stream == NULL)
-               return;
-
-       switch (stream_msg) {
-       case IPC_STR_STAGE_MESSAGE:
-       case IPC_STR_NOTIFICATION:
-               break;
-       case IPC_STR_RESET:
-               trace_ipc_notification("stream reset", stream->reply.stream_hw_id);
-               break;
-       case IPC_STR_PAUSE:
-               stream->running = false;
-               trace_ipc_notification("stream paused",
-                       stream->reply.stream_hw_id);
-               break;
-       case IPC_STR_RESUME:
-               stream->running = true;
-               trace_ipc_notification("stream running",
-                       stream->reply.stream_hw_id);
-               break;
-       }
-}
-
-static int hsw_process_reply(struct sst_hsw *hsw, u32 header)
-{
-       struct ipc_message *msg;
-       u32 reply = msg_get_global_reply(header);
-
-       trace_ipc_reply("processing -->", header);
-
-       msg = reply_find_msg(hsw, header);
-       if (msg == NULL) {
-               trace_ipc_error("error: can't find message header", header);
-               return -EIO;
-       }
-
-       /* first process the header */
-       switch (reply) {
-       case IPC_GLB_REPLY_PENDING:
-               trace_ipc_pending_reply("received", header);
-               msg->pending = true;
-               hsw->pending = true;
-               return 1;
-       case IPC_GLB_REPLY_SUCCESS:
-               if (msg->pending) {
-                       trace_ipc_pending_reply("completed", header);
-                       sst_dsp_inbox_read(hsw->dsp, msg->rx_data,
-                               msg->rx_size);
-                       hsw->pending = false;
-               } else {
-                       /* copy data from the DSP */
-                       sst_dsp_outbox_read(hsw->dsp, msg->rx_data,
-                               msg->rx_size);
-               }
-               break;
-       /* these will be rare - but useful for debug */
-       case IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE:
-               trace_ipc_error("error: unknown message type", header);
-               msg->errno = -EBADMSG;
-               break;
-       case IPC_GLB_REPLY_OUT_OF_RESOURCES:
-               trace_ipc_error("error: out of resources", header);
-               msg->errno = -ENOMEM;
-               break;
-       case IPC_GLB_REPLY_BUSY:
-               trace_ipc_error("error: reply busy", header);
-               msg->errno = -EBUSY;
-               break;
-       case IPC_GLB_REPLY_FAILURE:
-               trace_ipc_error("error: reply failure", header);
-               msg->errno = -EINVAL;
-               break;
-       case IPC_GLB_REPLY_STAGE_UNINITIALIZED:
-               trace_ipc_error("error: stage uninitialized", header);
-               msg->errno = -EINVAL;
-               break;
-       case IPC_GLB_REPLY_NOT_FOUND:
-               trace_ipc_error("error: reply not found", header);
-               msg->errno = -EINVAL;
-               break;
-       case IPC_GLB_REPLY_SOURCE_NOT_STARTED:
-               trace_ipc_error("error: source not started", header);
-               msg->errno = -EINVAL;
-               break;
-       case IPC_GLB_REPLY_INVALID_REQUEST:
-               trace_ipc_error("error: invalid request", header);
-               msg->errno = -EINVAL;
-               break;
-       case IPC_GLB_REPLY_ERROR_INVALID_PARAM:
-               trace_ipc_error("error: invalid parameter", header);
-               msg->errno = -EINVAL;
-               break;
-       default:
-               trace_ipc_error("error: unknown reply", header);
-               msg->errno = -EINVAL;
-               break;
-       }
-
-       /* update any stream states */
-       if (msg_get_global_type(header) == IPC_GLB_STREAM_MESSAGE)
-               hsw_stream_update(hsw, msg);
-
-       /* wake up and return the error if we have waiters on this message ? */
-       list_del(&msg->list);
-       tx_msg_reply_complete(hsw, msg);
-
-       return 1;
-}
-
-static int hsw_stream_message(struct sst_hsw *hsw, u32 header)
-{
-       u32 stream_msg, stream_id, stage_type;
-       struct sst_hsw_stream *stream;
-       int handled = 0;
-
-       stream_msg = msg_get_stream_type(header);
-       stream_id = msg_get_stream_id(header);
-       stage_type = msg_get_stage_type(header);
-
-       stream = get_stream_by_id(hsw, stream_id);
-       if (stream == NULL)
-               return handled;
-
-       stream->header = header;
-
-       switch (stream_msg) {
-       case IPC_STR_STAGE_MESSAGE:
-               dev_err(hsw->dev, "error: stage msg not implemented 0x%8.8x\n",
-                       header);
-               break;
-       case IPC_STR_NOTIFICATION:
-               schedule_work(&stream->notify_work);
-               break;
-       default:
-               /* handle pending message complete request */
-               handled = hsw_process_reply(hsw, header);
-               break;
-       }
-
-       return handled;
-}
-
-static int hsw_log_message(struct sst_hsw *hsw, u32 header)
-{
-       u32 operation = (header & IPC_LOG_OP_MASK) >>  IPC_LOG_OP_SHIFT;
-       struct sst_hsw_log_stream *stream = &hsw->log_stream;
-       int ret = 1;
-
-       if (operation != IPC_DEBUG_REQUEST_LOG_DUMP) {
-               dev_err(hsw->dev,
-                       "error: log msg not implemented 0x%8.8x\n", header);
-               return 0;
-       }
-
-       mutex_lock(&stream->rw_mutex);
-       stream->last_pos = stream->curr_pos;
-       sst_dsp_inbox_read(
-               hsw->dsp, &stream->curr_pos, sizeof(stream->curr_pos));
-       mutex_unlock(&stream->rw_mutex);
-
-       schedule_work(&stream->notify_work);
-
-       return ret;
-}
-
-static int hsw_process_notification(struct sst_hsw *hsw)
-{
-       struct sst_dsp *sst = hsw->dsp;
-       u32 type, header;
-       int handled = 1;
-
-       header = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
-       type = msg_get_global_type(header);
-
-       trace_ipc_request("processing -->", header);
-
-       /* FW Ready is a special case */
-       if (!hsw->boot_complete && header & IPC_FW_READY) {
-               hsw_fw_ready(hsw, header);
-               return handled;
-       }
-
-       switch (type) {
-       case IPC_GLB_GET_FW_VERSION:
-       case IPC_GLB_ALLOCATE_STREAM:
-       case IPC_GLB_FREE_STREAM:
-       case IPC_GLB_GET_FW_CAPABILITIES:
-       case IPC_GLB_REQUEST_DUMP:
-       case IPC_GLB_GET_DEVICE_FORMATS:
-       case IPC_GLB_SET_DEVICE_FORMATS:
-       case IPC_GLB_ENTER_DX_STATE:
-       case IPC_GLB_GET_MIXER_STREAM_INFO:
-       case IPC_GLB_MAX_IPC_MESSAGE_TYPE:
-       case IPC_GLB_RESTORE_CONTEXT:
-       case IPC_GLB_SHORT_REPLY:
-               dev_err(hsw->dev, "error: message type %d header 0x%x\n",
-                       type, header);
-               break;
-       case IPC_GLB_STREAM_MESSAGE:
-               handled = hsw_stream_message(hsw, header);
-               break;
-       case IPC_GLB_DEBUG_LOG_MESSAGE:
-               handled = hsw_log_message(hsw, header);
-               break;
-       default:
-               dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n",
-                       type, header);
-               break;
-       }
-
-       return handled;
-}
-
-static irqreturn_t hsw_irq_thread(int irq, void *context)
-{
-       struct sst_dsp *sst = (struct sst_dsp *) context;
-       struct sst_hsw *hsw = sst_dsp_get_thread_context(sst);
-       u32 ipcx, ipcd;
-       int handled;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-
-       ipcx = sst_dsp_ipc_msg_rx(hsw->dsp);
-       ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
-
-       /* reply message from DSP */
-       if (ipcx & SST_IPCX_DONE) {
-
-               /* Handle Immediate reply from DSP Core */
-               handled = hsw_process_reply(hsw, ipcx);
-
-               if (handled > 0) {
-                       /* clear DONE bit - tell DSP we have completed */
-                       sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
-                               SST_IPCX_DONE, 0);
-
-                       /* unmask Done interrupt */
-                       sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
-                               SST_IMRX_DONE, 0);
-               }
-       }
-
-       /* new message from DSP */
-       if (ipcd & SST_IPCD_BUSY) {
-
-               /* Handle Notification and Delayed reply from DSP Core */
-               handled = hsw_process_notification(hsw);
-
-               /* clear BUSY bit and set DONE bit - accept new messages */
-               if (handled > 0) {
-                       sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
-                               SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
-
-                       /* unmask busy interrupt */
-                       sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
-                               SST_IMRX_BUSY, 0);
-               }
-       }
-
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       /* continue to send any remaining messages... */
-       queue_kthread_work(&hsw->kworker, &hsw->kwork);
-
-       return IRQ_HANDLED;
-}
-
-int sst_hsw_fw_get_version(struct sst_hsw *hsw,
-       struct sst_hsw_ipc_fw_version *version)
-{
-       int ret;
-
-       ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION),
-               NULL, 0, version, sizeof(*version));
-       if (ret < 0)
-               dev_err(hsw->dev, "error: get version failed\n");
-
-       return ret;
-}
-
-/* Mixer Controls */
-int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 stage_id, u32 channel, u32 *volume)
-{
-       if (channel > 1)
-               return -EINVAL;
-
-       sst_dsp_read(hsw->dsp, volume,
-               stream->reply.volume_register_address[channel],
-               sizeof(*volume));
-
-       return 0;
-}
-
-/* stream volume */
-int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume)
-{
-       struct sst_hsw_ipc_volume_req *req;
-       u32 header;
-       int ret;
-
-       trace_ipc_request("set stream volume", stream->reply.stream_hw_id);
-
-       if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL)
-               return -EINVAL;
-
-       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
-               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
-       header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
-       header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
-       header |= (stage_id << IPC_STG_ID_SHIFT);
-
-       req = &stream->vol_req;
-       req->target_volume = volume;
-
-       /* set both at same time ? */
-       if (channel == SST_HSW_CHANNELS_ALL) {
-               if (hsw->mute[0] && hsw->mute[1]) {
-                       hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
-                       return 0;
-               } else if (hsw->mute[0])
-                       req->channel = 1;
-               else if (hsw->mute[1])
-                       req->channel = 0;
-               else
-                       req->channel = SST_HSW_CHANNELS_ALL;
-       } else {
-               /* set only 1 channel */
-               if (hsw->mute[channel]) {
-                       hsw->mute_volume[channel] = volume;
-                       return 0;
-               }
-               req->channel = channel;
-       }
-
-       ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: set stream volume failed\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
-       u32 *volume)
-{
-       if (channel > 1)
-               return -EINVAL;
-
-       sst_dsp_read(hsw->dsp, volume,
-               hsw->mixer_info.volume_register_address[channel],
-               sizeof(*volume));
-
-       return 0;
-}
-
-/* global mixer volume */
-int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
-       u32 volume)
-{
-       struct sst_hsw_ipc_volume_req req;
-       u32 header;
-       int ret;
-
-       trace_ipc_request("set mixer volume", volume);
-
-       if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL)
-               return -EINVAL;
-
-       /* set both at same time ? */
-       if (channel == SST_HSW_CHANNELS_ALL) {
-               if (hsw->mute[0] && hsw->mute[1]) {
-                       hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
-                       return 0;
-               } else if (hsw->mute[0])
-                       req.channel = 1;
-               else if (hsw->mute[1])
-                       req.channel = 0;
-               else
-                       req.channel = SST_HSW_CHANNELS_ALL;
-       } else {
-               /* set only 1 channel */
-               if (hsw->mute[channel]) {
-                       hsw->mute_volume[channel] = volume;
-                       return 0;
-               }
-               req.channel = channel;
-       }
-
-       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
-               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
-       header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT);
-       header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
-       header |= (stage_id << IPC_STG_ID_SHIFT);
-
-       req.curve_duration = hsw->curve_duration;
-       req.curve_type = hsw->curve_type;
-       req.target_volume = volume;
-
-       ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: set mixer volume failed\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-/* Stream API */
-struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
-       u32 (*notify_position)(struct sst_hsw_stream *stream, void *data),
-       void *data)
-{
-       struct sst_hsw_stream *stream;
-       struct sst_dsp *sst = hsw->dsp;
-       unsigned long flags;
-
-       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-       if (stream == NULL)
-               return NULL;
-
-       spin_lock_irqsave(&sst->spinlock, flags);
-       stream->reply.stream_hw_id = INVALID_STREAM_HW_ID;
-       list_add(&stream->node, &hsw->stream_list);
-       stream->notify_position = notify_position;
-       stream->pdata = data;
-       stream->hsw = hsw;
-       stream->host_id = id;
-
-       /* work to process notification messages */
-       INIT_WORK(&stream->notify_work, hsw_notification_work);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       return stream;
-}
-
-int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
-{
-       u32 header;
-       int ret = 0;
-       struct sst_dsp *sst = hsw->dsp;
-       unsigned long flags;
-
-       if (!stream) {
-               dev_warn(hsw->dev, "warning: stream is NULL, no stream to free, ignore it.\n");
-               return 0;
-       }
-
-       /* dont free DSP streams that are not commited */
-       if (!stream->commited)
-               goto out;
-
-       trace_ipc_request("stream free", stream->host_id);
-
-       stream->free_req.stream_id = stream->reply.stream_hw_id;
-       header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM);
-
-       ret = ipc_tx_message_wait(hsw, header, &stream->free_req,
-               sizeof(stream->free_req), NULL, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: free stream %d failed\n",
-                       stream->free_req.stream_id);
-               return -EAGAIN;
-       }
-
-       trace_hsw_stream_free_req(stream, &stream->free_req);
-
-out:
-       cancel_work_sync(&stream->notify_work);
-       spin_lock_irqsave(&sst->spinlock, flags);
-       list_del(&stream->node);
-       kfree(stream);
-       spin_unlock_irqrestore(&sst->spinlock, flags);
-
-       return ret;
-}
-
-int sst_hsw_stream_set_bits(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, enum sst_hsw_bitdepth bits)
-{
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for set bits\n");
-               return -EINVAL;
-       }
-
-       stream->request.format.bitdepth = bits;
-       return 0;
-}
-
-int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, int channels)
-{
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for set channels\n");
-               return -EINVAL;
-       }
-
-       stream->request.format.ch_num = channels;
-       return 0;
-}
-
-int sst_hsw_stream_set_rate(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, int rate)
-{
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for set rate\n");
-               return -EINVAL;
-       }
-
-       stream->request.format.frequency = rate;
-       return 0;
-}
-
-int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 map,
-       enum sst_hsw_channel_config config)
-{
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for set map\n");
-               return -EINVAL;
-       }
-
-       stream->request.format.map = map;
-       stream->request.format.config = config;
-       return 0;
-}
-
-int sst_hsw_stream_set_style(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, enum sst_hsw_interleaving style)
-{
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for set style\n");
-               return -EINVAL;
-       }
-
-       stream->request.format.style = style;
-       return 0;
-}
-
-int sst_hsw_stream_set_valid(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 bits)
-{
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for set valid bits\n");
-               return -EINVAL;
-       }
-
-       stream->request.format.valid_bit = bits;
-       return 0;
-}
-
-/* Stream Configuration */
-int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       enum sst_hsw_stream_path_id path_id,
-       enum sst_hsw_stream_type stream_type,
-       enum sst_hsw_stream_format format_id)
-{
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for set format\n");
-               return -EINVAL;
-       }
-
-       stream->request.path_id = path_id;
-       stream->request.stream_type = stream_type;
-       stream->request.format_id = format_id;
-
-       trace_hsw_stream_alloc_request(stream, &stream->request);
-
-       return 0;
-}
-
-int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 ring_pt_address, u32 num_pages,
-       u32 ring_size, u32 ring_offset, u32 ring_first_pfn)
-{
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for buffer\n");
-               return -EINVAL;
-       }
-
-       stream->request.ringinfo.ring_pt_address = ring_pt_address;
-       stream->request.ringinfo.num_pages = num_pages;
-       stream->request.ringinfo.ring_size = ring_size;
-       stream->request.ringinfo.ring_offset = ring_offset;
-       stream->request.ringinfo.ring_first_pfn = ring_first_pfn;
-
-       trace_hsw_stream_buffer(stream);
-
-       return 0;
-}
-
-int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, struct sst_module_runtime *runtime)
-{
-       struct sst_hsw_module_map *map = &stream->request.map;
-       struct sst_dsp *dsp = sst_hsw_get_dsp(hsw);
-       struct sst_module *module = runtime->module;
-
-       if (stream->commited) {
-               dev_err(hsw->dev, "error: stream committed for set module\n");
-               return -EINVAL;
-       }
-
-       /* only support initial module atm */
-       map->module_entries_count = 1;
-       map->module_entries[0].module_id = module->id;
-       map->module_entries[0].entry_point = module->entry;
-
-       stream->request.persistent_mem.offset =
-               sst_dsp_get_offset(dsp, runtime->persistent_offset, SST_MEM_DRAM);
-       stream->request.persistent_mem.size = module->persistent_size;
-
-       stream->request.scratch_mem.offset =
-               sst_dsp_get_offset(dsp, dsp->scratch_offset, SST_MEM_DRAM);
-       stream->request.scratch_mem.size = dsp->scratch_size;
-
-       dev_dbg(hsw->dev, "module %d runtime %d using:\n", module->id,
-               runtime->id);
-       dev_dbg(hsw->dev, " persistent offset 0x%x bytes 0x%x\n",
-               stream->request.persistent_mem.offset,
-               stream->request.persistent_mem.size);
-       dev_dbg(hsw->dev, " scratch offset 0x%x bytes 0x%x\n",
-               stream->request.scratch_mem.offset,
-               stream->request.scratch_mem.size);
-
-       return 0;
-}
-
-int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
-{
-       struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request;
-       struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply;
-       u32 header;
-       int ret;
-
-       if (!stream) {
-               dev_warn(hsw->dev, "warning: stream is NULL, no stream to commit, ignore it.\n");
-               return 0;
-       }
-
-       if (stream->commited) {
-               dev_warn(hsw->dev, "warning: stream is already committed, ignore it.\n");
-               return 0;
-       }
-
-       trace_ipc_request("stream alloc", stream->host_id);
-
-       header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM);
-
-       ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req),
-               reply, sizeof(*reply));
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: stream commit failed\n");
-               return ret;
-       }
-
-       stream->commited = 1;
-       trace_hsw_stream_alloc_reply(stream);
-
-       return 0;
-}
-
-snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream)
-{
-       return stream->old_position;
-}
-
-void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, snd_pcm_uframes_t val)
-{
-       stream->old_position = val;
-}
-
-bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream)
-{
-       return stream->play_silence;
-}
-
-void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, bool val)
-{
-       stream->play_silence = val;
-}
-
-/* Stream Information - these calls could be inline but we want the IPC
- ABI to be opaque to client PCM drivers to cope with any future ABI changes */
-int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
-{
-       struct sst_hsw_ipc_stream_info_reply *reply;
-       u32 header;
-       int ret;
-
-       reply = &hsw->mixer_info;
-       header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO);
-
-       trace_ipc_request("get global mixer info", 0);
-
-       ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply));
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: get stream info failed\n");
-               return ret;
-       }
-
-       trace_hsw_mixer_info_reply(reply);
-
-       return 0;
-}
-
-/* Send stream command */
-static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type,
-       int stream_id, int wait)
-{
-       u32 header;
-
-       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type);
-       header |= (stream_id << IPC_STR_ID_SHIFT);
-
-       if (wait)
-               return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0);
-       else
-               return ipc_tx_message_nowait(hsw, header, NULL, 0);
-}
-
-/* Stream ALSA trigger operations */
-int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       int wait)
-{
-       int ret;
-
-       if (!stream) {
-               dev_warn(hsw->dev, "warning: stream is NULL, no stream to pause, ignore it.\n");
-               return 0;
-       }
-
-       trace_ipc_request("stream pause", stream->reply.stream_hw_id);
-
-       ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE,
-               stream->reply.stream_hw_id, wait);
-       if (ret < 0)
-               dev_err(hsw->dev, "error: failed to pause stream %d\n",
-                       stream->reply.stream_hw_id);
-
-       return ret;
-}
-
-int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       int wait)
-{
-       int ret;
-
-       if (!stream) {
-               dev_warn(hsw->dev, "warning: stream is NULL, no stream to resume, ignore it.\n");
-               return 0;
-       }
-
-       trace_ipc_request("stream resume", stream->reply.stream_hw_id);
-
-       ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME,
-               stream->reply.stream_hw_id, wait);
-       if (ret < 0)
-               dev_err(hsw->dev, "error: failed to resume stream %d\n",
-                       stream->reply.stream_hw_id);
-
-       return ret;
-}
-
-int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
-{
-       int ret, tries = 10;
-
-       if (!stream) {
-               dev_warn(hsw->dev, "warning: stream is NULL, no stream to reset, ignore it.\n");
-               return 0;
-       }
-
-       /* dont reset streams that are not commited */
-       if (!stream->commited)
-               return 0;
-
-       /* wait for pause to complete before we reset the stream */
-       while (stream->running && tries--)
-               msleep(1);
-       if (!tries) {
-               dev_err(hsw->dev, "error: reset stream %d still running\n",
-                       stream->reply.stream_hw_id);
-               return -EINVAL;
-       }
-
-       trace_ipc_request("stream reset", stream->reply.stream_hw_id);
-
-       ret = sst_hsw_stream_operations(hsw, IPC_STR_RESET,
-               stream->reply.stream_hw_id, 1);
-       if (ret < 0)
-               dev_err(hsw->dev, "error: failed to reset stream %d\n",
-                       stream->reply.stream_hw_id);
-       return ret;
-}
-
-/* Stream pointer positions */
-u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream)
-{
-       u32 rpos;
-
-       sst_dsp_read(hsw->dsp, &rpos,
-               stream->reply.read_position_register_address, sizeof(rpos));
-
-       return rpos;
-}
-
-/* Stream presentation (monotonic) positions */
-u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream)
-{
-       u64 ppos;
-
-       sst_dsp_read(hsw->dsp, &ppos,
-               stream->reply.presentation_position_register_address,
-               sizeof(ppos));
-
-       return ppos;
-}
-
-/* physical BE config */
-int sst_hsw_device_set_config(struct sst_hsw *hsw,
-       enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
-       enum sst_hsw_device_mode mode, u32 clock_divider)
-{
-       struct sst_hsw_ipc_device_config_req config;
-       u32 header;
-       int ret;
-
-       trace_ipc_request("set device config", dev);
-
-       config.ssp_interface = dev;
-       config.clock_frequency = mclk;
-       config.mode = mode;
-       config.clock_divider = clock_divider;
-       if (mode == SST_HSW_DEVICE_TDM_CLOCK_MASTER)
-               config.channels = 4;
-       else
-               config.channels = 2;
-
-       trace_hsw_device_config_req(&config);
-
-       header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS);
-
-       ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config),
-               NULL, 0);
-       if (ret < 0)
-               dev_err(hsw->dev, "error: set device formats failed\n");
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_hsw_device_set_config);
-
-/* DX Config */
-int sst_hsw_dx_set_state(struct sst_hsw *hsw,
-       enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx)
-{
-       u32 header, state_;
-       int ret, item;
-
-       header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE);
-       state_ = state;
-
-       trace_ipc_request("PM enter Dx state", state);
-
-       ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_),
-               dx, sizeof(*dx));
-       if (ret < 0) {
-               dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state);
-               return ret;
-       }
-
-       for (item = 0; item < dx->entries_no; item++) {
-               dev_dbg(hsw->dev,
-                       "Item[%d] offset[%x] - size[%x] - source[%x]\n",
-                       item, dx->mem_info[item].offset,
-                       dx->mem_info[item].size,
-                       dx->mem_info[item].source);
-       }
-       dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n",
-               dx->entries_no, state);
-
-       return ret;
-}
-
-struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
-       int mod_id, int offset)
-{
-       struct sst_dsp *dsp = hsw->dsp;
-       struct sst_module *module;
-       struct sst_module_runtime *runtime;
-       int err;
-
-       module = sst_module_get_from_id(dsp, mod_id);
-       if (module == NULL) {
-               dev_err(dsp->dev, "error: failed to get module %d for pcm\n",
-                       mod_id);
-               return NULL;
-       }
-
-       runtime = sst_module_runtime_new(module, mod_id, NULL);
-       if (runtime == NULL) {
-               dev_err(dsp->dev, "error: failed to create module %d runtime\n",
-                       mod_id);
-               return NULL;
-       }
-
-       err = sst_module_runtime_alloc_blocks(runtime, offset);
-       if (err < 0) {
-               dev_err(dsp->dev, "error: failed to alloc blocks for module %d runtime\n",
-                       mod_id);
-               sst_module_runtime_free(runtime);
-               return NULL;
-       }
-
-       dev_dbg(dsp->dev, "runtime id %d created for module %d\n", runtime->id,
-               mod_id);
-       return runtime;
-}
-
-void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime)
-{
-       sst_module_runtime_free_blocks(runtime);
-       sst_module_runtime_free(runtime);
-}
-
-#ifdef CONFIG_PM
-static int sst_hsw_dx_state_dump(struct sst_hsw *hsw)
-{
-       struct sst_dsp *sst = hsw->dsp;
-       u32 item, offset, size;
-       int ret = 0;
-
-       trace_ipc_request("PM state dump. Items #", SST_HSW_MAX_DX_REGIONS);
-
-       if (hsw->dx.entries_no > SST_HSW_MAX_DX_REGIONS) {
-               dev_err(hsw->dev,
-                       "error: number of FW context regions greater than %d\n",
-                       SST_HSW_MAX_DX_REGIONS);
-               memset(&hsw->dx, 0, sizeof(hsw->dx));
-               return -EINVAL;
-       }
-
-       ret = sst_dsp_dma_get_channel(sst, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
-               return ret;
-       }
-
-       /* set on-demond mode on engine 0 channel 3 */
-       sst_dsp_shim_update_bits(sst, SST_HMDC,
-                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
-                       SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH);
-
-       for (item = 0; item < hsw->dx.entries_no; item++) {
-               if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP
-                       && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET
-                       && hsw->dx.mem_info[item].offset <
-                       DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) {
-
-                       offset = hsw->dx.mem_info[item].offset
-                                       - DSP_DRAM_ADDR_OFFSET;
-                       size = (hsw->dx.mem_info[item].size + 3) & (~3);
-
-                       ret = sst_dsp_dma_copyfrom(sst, hsw->dx_context_paddr + offset,
-                               sst->addr.lpe_base + offset, size);
-                       if (ret < 0) {
-                               dev_err(hsw->dev,
-                                       "error: FW context dump failed\n");
-                               memset(&hsw->dx, 0, sizeof(hsw->dx));
-                               goto out;
-                       }
-               }
-       }
-
-out:
-       sst_dsp_dma_put_channel(sst);
-       return ret;
-}
-
-static int sst_hsw_dx_state_restore(struct sst_hsw *hsw)
-{
-       struct sst_dsp *sst = hsw->dsp;
-       u32 item, offset, size;
-       int ret;
-
-       for (item = 0; item < hsw->dx.entries_no; item++) {
-               if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP
-                       && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET
-                       && hsw->dx.mem_info[item].offset <
-                       DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) {
-
-                       offset = hsw->dx.mem_info[item].offset
-                                       - DSP_DRAM_ADDR_OFFSET;
-                       size = (hsw->dx.mem_info[item].size + 3) & (~3);
-
-                       ret = sst_dsp_dma_copyto(sst, sst->addr.lpe_base + offset,
-                               hsw->dx_context_paddr + offset, size);
-                       if (ret < 0) {
-                               dev_err(hsw->dev,
-                                       "error: FW context restore failed\n");
-                               return ret;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static void sst_hsw_drop_all(struct sst_hsw *hsw)
-{
-       struct ipc_message *msg, *tmp;
-       unsigned long flags;
-       int tx_drop_cnt = 0, rx_drop_cnt = 0;
-
-       /* drop all TX and Rx messages before we stall + reset DSP */
-       spin_lock_irqsave(&hsw->dsp->spinlock, flags);
-
-       list_for_each_entry_safe(msg, tmp, &hsw->tx_list, list) {
-               list_move(&msg->list, &hsw->empty_list);
-               tx_drop_cnt++;
-       }
-
-       list_for_each_entry_safe(msg, tmp, &hsw->rx_list, list) {
-               list_move(&msg->list, &hsw->empty_list);
-               rx_drop_cnt++;
-       }
-
-       spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
-
-       if (tx_drop_cnt || rx_drop_cnt)
-               dev_err(hsw->dev, "dropped IPC msg RX=%d, TX=%d\n",
-                       tx_drop_cnt, rx_drop_cnt);
-}
-
-int sst_hsw_dsp_load(struct sst_hsw *hsw)
-{
-       struct sst_dsp *dsp = hsw->dsp;
-       int ret;
-
-       dev_dbg(hsw->dev, "loading audio DSP....");
-
-       ret = sst_dsp_wake(dsp);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: failed to wake audio DSP\n");
-               return -ENODEV;
-       }
-
-       ret = sst_dsp_dma_get_channel(dsp, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
-               return ret;
-       }
-
-       ret = sst_fw_reload(hsw->sst_fw);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: SST FW reload failed\n");
-               sst_dsp_dma_put_channel(dsp);
-               return -ENOMEM;
-       }
-
-       sst_dsp_dma_put_channel(dsp);
-       return 0;
-}
-
-static int sst_hsw_dsp_restore(struct sst_hsw *hsw)
-{
-       struct sst_dsp *dsp = hsw->dsp;
-       int ret;
-
-       dev_dbg(hsw->dev, "restoring audio DSP....");
-
-       ret = sst_dsp_dma_get_channel(dsp, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
-               return ret;
-       }
-
-       ret = sst_hsw_dx_state_restore(hsw);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: SST FW context restore failed\n");
-               sst_dsp_dma_put_channel(dsp);
-               return -ENOMEM;
-       }
-       sst_dsp_dma_put_channel(dsp);
-
-       /* wait for DSP boot completion */
-       sst_dsp_boot(dsp);
-
-       return ret;
-}
-
-int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw)
-{
-       int ret;
-
-       dev_dbg(hsw->dev, "audio dsp runtime suspend\n");
-
-       ret = sst_hsw_dx_set_state(hsw, SST_HSW_DX_STATE_D3, &hsw->dx);
-       if (ret < 0)
-               return ret;
-
-       sst_dsp_stall(hsw->dsp);
-
-       ret = sst_hsw_dx_state_dump(hsw);
-       if (ret < 0)
-               return ret;
-
-       sst_hsw_drop_all(hsw);
-
-       return 0;
-}
-
-int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw)
-{
-       sst_fw_unload(hsw->sst_fw);
-       sst_block_free_scratch(hsw->dsp);
-
-       hsw->boot_complete = false;
-
-       sst_dsp_sleep(hsw->dsp);
-
-       return 0;
-}
-
-int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw)
-{
-       struct device *dev = hsw->dev;
-       int ret;
-
-       dev_dbg(dev, "audio dsp runtime resume\n");
-
-       if (hsw->boot_complete)
-               return 1; /* tell caller no action is required */
-
-       ret = sst_hsw_dsp_restore(hsw);
-       if (ret < 0)
-               dev_err(dev, "error: audio DSP boot failure\n");
-
-       ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
-               msecs_to_jiffies(IPC_BOOT_MSECS));
-       if (ret == 0) {
-               dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n",
-                       sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD),
-                       sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX));
-               return -EIO;
-       }
-
-       /* Set ADSP SSP port settings */
-       ret = sst_hsw_device_set_config(hsw, SST_HSW_DEVICE_SSP_0,
-                                       SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
-                                       SST_HSW_DEVICE_CLOCK_MASTER, 9);
-       if (ret < 0)
-               dev_err(dev, "error: SSP re-initialization failed\n");
-
-       return ret;
-}
-#endif
-
-static int msg_empty_list_init(struct sst_hsw *hsw)
-{
-       int i;
-
-       hsw->msg = kzalloc(sizeof(struct ipc_message) *
-               IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
-       if (hsw->msg == NULL)
-               return -ENOMEM;
-
-       for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
-               init_waitqueue_head(&hsw->msg[i].waitq);
-               list_add(&hsw->msg[i].list, &hsw->empty_list);
-       }
-
-       return 0;
-}
-
-struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw)
-{
-       return hsw->dsp;
-}
-
-static struct sst_dsp_device hsw_dev = {
-       .thread = hsw_irq_thread,
-       .ops = &haswell_ops,
-};
-
-int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_hsw_ipc_fw_version version;
-       struct sst_hsw *hsw;
-       int ret;
-
-       dev_dbg(dev, "initialising Audio DSP IPC\n");
-
-       hsw = devm_kzalloc(dev, sizeof(*hsw), GFP_KERNEL);
-       if (hsw == NULL)
-               return -ENOMEM;
-
-       hsw->dev = dev;
-       INIT_LIST_HEAD(&hsw->stream_list);
-       INIT_LIST_HEAD(&hsw->tx_list);
-       INIT_LIST_HEAD(&hsw->rx_list);
-       INIT_LIST_HEAD(&hsw->empty_list);
-       init_waitqueue_head(&hsw->boot_wait);
-       init_waitqueue_head(&hsw->wait_txq);
-
-       ret = msg_empty_list_init(hsw);
-       if (ret < 0)
-               return -ENOMEM;
-
-       /* start the IPC message thread */
-       init_kthread_worker(&hsw->kworker);
-       hsw->tx_thread = kthread_run(kthread_worker_fn,
-                                          &hsw->kworker, "%s",
-                                          dev_name(hsw->dev));
-       if (IS_ERR(hsw->tx_thread)) {
-               ret = PTR_ERR(hsw->tx_thread);
-               dev_err(hsw->dev, "error: failed to create message TX task\n");
-               goto err_free_msg;
-       }
-       init_kthread_work(&hsw->kwork, ipc_tx_msgs);
-
-       hsw_dev.thread_context = hsw;
-
-       /* init SST shim */
-       hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata);
-       if (hsw->dsp == NULL) {
-               ret = -ENODEV;
-               goto dsp_err;
-       }
-
-       /* allocate DMA buffer for context storage */
-       hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev,
-               SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL);
-       if (hsw->dx_context == NULL) {
-               ret = -ENOMEM;
-               goto dma_err;
-       }
-
-       /* keep the DSP in reset state for base FW loading */
-       sst_dsp_reset(hsw->dsp);
-
-       hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw);
-       if (hsw->sst_fw == NULL) {
-               ret = -ENODEV;
-               dev_err(dev, "error: failed to load firmware\n");
-               goto fw_err;
-       }
-
-       /* wait for DSP boot completion */
-       sst_dsp_boot(hsw->dsp);
-       ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
-               msecs_to_jiffies(IPC_BOOT_MSECS));
-       if (ret == 0) {
-               ret = -EIO;
-               dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n",
-                       sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD),
-                       sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX));
-               goto boot_err;
-       }
-
-       /* get the FW version */
-       sst_hsw_fw_get_version(hsw, &version);
-
-       /* get the globalmixer */
-       ret = sst_hsw_mixer_get_info(hsw);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: failed to get stream info\n");
-               goto boot_err;
-       }
-
-       pdata->dsp = hsw;
-       return 0;
-
-boot_err:
-       sst_dsp_reset(hsw->dsp);
-       sst_fw_free(hsw->sst_fw);
-fw_err:
-       dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
-                       hsw->dx_context, hsw->dx_context_paddr);
-dma_err:
-       sst_dsp_free(hsw->dsp);
-dsp_err:
-       kthread_stop(hsw->tx_thread);
-err_free_msg:
-       kfree(hsw->msg);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_hsw_dsp_init);
-
-void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_hsw *hsw = pdata->dsp;
-
-       sst_dsp_reset(hsw->dsp);
-       sst_fw_free_all(hsw->dsp);
-       dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
-                       hsw->dx_context, hsw->dx_context_paddr);
-       sst_dsp_free(hsw->dsp);
-       kthread_stop(hsw->tx_thread);
-       kfree(hsw->msg);
-}
-EXPORT_SYMBOL_GPL(sst_hsw_dsp_free);
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
deleted file mode 100644 (file)
index 8580960..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Intel SST Haswell/Broadwell IPC Support
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __SST_HASWELL_IPC_H
-#define __SST_HASWELL_IPC_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <sound/asound.h>
-
-#define SST_HSW_NO_CHANNELS            4
-#define SST_HSW_MAX_DX_REGIONS         14
-#define SST_HSW_DX_CONTEXT_SIZE        (640 * 1024)
-#define SST_HSW_CHANNELS_ALL           0xffffffff
-
-#define SST_HSW_FW_LOG_CONFIG_DWORDS   12
-#define SST_HSW_GLOBAL_LOG             15
-
-/**
- * Upfront defined maximum message size that is
- * expected by the in/out communication pipes in FW.
- */
-#define SST_HSW_IPC_MAX_PAYLOAD_SIZE   400
-#define SST_HSW_MAX_INFO_SIZE          64
-#define SST_HSW_BUILD_HASH_LENGTH      40
-
-struct sst_hsw;
-struct sst_hsw_stream;
-struct sst_hsw_log_stream;
-struct sst_pdata;
-struct sst_module;
-struct sst_module_runtime;
-extern struct sst_ops haswell_ops;
-
-/* Stream Allocate Path ID */
-enum sst_hsw_stream_path_id {
-       SST_HSW_STREAM_PATH_SSP0_OUT = 0,
-       SST_HSW_STREAM_PATH_SSP0_IN = 1,
-       SST_HSW_STREAM_PATH_MAX_PATH_ID = 2,
-};
-
-/* Stream Allocate Stream Type */
-enum sst_hsw_stream_type {
-       SST_HSW_STREAM_TYPE_RENDER = 0,
-       SST_HSW_STREAM_TYPE_SYSTEM = 1,
-       SST_HSW_STREAM_TYPE_CAPTURE = 2,
-       SST_HSW_STREAM_TYPE_LOOPBACK = 3,
-       SST_HSW_STREAM_TYPE_MAX_STREAM_TYPE = 4,
-};
-
-/* Stream Allocate Stream Format */
-enum sst_hsw_stream_format {
-       SST_HSW_STREAM_FORMAT_PCM_FORMAT = 0,
-       SST_HSW_STREAM_FORMAT_MP3_FORMAT = 1,
-       SST_HSW_STREAM_FORMAT_AAC_FORMAT = 2,
-       SST_HSW_STREAM_FORMAT_MAX_FORMAT_ID = 3,
-};
-
-/* Device ID */
-enum sst_hsw_device_id {
-       SST_HSW_DEVICE_SSP_0   = 0,
-       SST_HSW_DEVICE_SSP_1   = 1,
-};
-
-/* Device Master Clock Frequency */
-enum sst_hsw_device_mclk {
-       SST_HSW_DEVICE_MCLK_OFF         = 0,
-       SST_HSW_DEVICE_MCLK_FREQ_6_MHZ  = 1,
-       SST_HSW_DEVICE_MCLK_FREQ_12_MHZ = 2,
-       SST_HSW_DEVICE_MCLK_FREQ_24_MHZ = 3,
-};
-
-/* Device Clock Master */
-enum sst_hsw_device_mode {
-       SST_HSW_DEVICE_CLOCK_SLAVE   = 0,
-       SST_HSW_DEVICE_CLOCK_MASTER  = 1,
-       SST_HSW_DEVICE_TDM_CLOCK_MASTER = 2,
-};
-
-/* DX Power State */
-enum sst_hsw_dx_state {
-       SST_HSW_DX_STATE_D0     = 0,
-       SST_HSW_DX_STATE_D1     = 1,
-       SST_HSW_DX_STATE_D3     = 3,
-       SST_HSW_DX_STATE_MAX    = 3,
-};
-
-/* Audio stream stage IDs */
-enum sst_hsw_fx_stage_id {
-       SST_HSW_STAGE_ID_WAVES = 0,
-       SST_HSW_STAGE_ID_DTS   = 1,
-       SST_HSW_STAGE_ID_DOLBY = 2,
-       SST_HSW_STAGE_ID_BOOST = 3,
-       SST_HSW_STAGE_ID_MAX_FX_ID
-};
-
-/* DX State Type */
-enum sst_hsw_dx_type {
-       SST_HSW_DX_TYPE_FW_IMAGE = 0,
-       SST_HSW_DX_TYPE_MEMORY_DUMP = 1
-};
-
-/* Volume Curve Type*/
-enum sst_hsw_volume_curve {
-       SST_HSW_VOLUME_CURVE_NONE = 0,
-       SST_HSW_VOLUME_CURVE_FADE = 1
-};
-
-/* Sample ordering */
-enum sst_hsw_interleaving {
-       SST_HSW_INTERLEAVING_PER_CHANNEL = 0,
-       SST_HSW_INTERLEAVING_PER_SAMPLE  = 1,
-};
-
-/* Channel indices */
-enum sst_hsw_channel_index {
-       SST_HSW_CHANNEL_LEFT            = 0,
-       SST_HSW_CHANNEL_CENTER          = 1,
-       SST_HSW_CHANNEL_RIGHT           = 2,
-       SST_HSW_CHANNEL_LEFT_SURROUND   = 3,
-       SST_HSW_CHANNEL_CENTER_SURROUND = 3,
-       SST_HSW_CHANNEL_RIGHT_SURROUND  = 4,
-       SST_HSW_CHANNEL_LFE             = 7,
-       SST_HSW_CHANNEL_INVALID         = 0xF,
-};
-
-/* List of supported channel maps. */
-enum sst_hsw_channel_config {
-       SST_HSW_CHANNEL_CONFIG_MONO      = 0, /* mono only. */
-       SST_HSW_CHANNEL_CONFIG_STEREO    = 1, /* L & R. */
-       SST_HSW_CHANNEL_CONFIG_2_POINT_1 = 2, /* L, R & LFE; PCM only. */
-       SST_HSW_CHANNEL_CONFIG_3_POINT_0 = 3, /* L, C & R; MP3 & AAC only. */
-       SST_HSW_CHANNEL_CONFIG_3_POINT_1 = 4, /* L, C, R & LFE; PCM only. */
-       SST_HSW_CHANNEL_CONFIG_QUATRO    = 5, /* L, R, Ls & Rs; PCM only. */
-       SST_HSW_CHANNEL_CONFIG_4_POINT_0 = 6, /* L, C, R & Cs; MP3 & AAC only. */
-       SST_HSW_CHANNEL_CONFIG_5_POINT_0 = 7, /* L, C, R, Ls & Rs. */
-       SST_HSW_CHANNEL_CONFIG_5_POINT_1 = 8, /* L, C, R, Ls, Rs & LFE. */
-       SST_HSW_CHANNEL_CONFIG_DUAL_MONO = 9, /* One channel replicated in two. */
-       SST_HSW_CHANNEL_CONFIG_INVALID,
-};
-
-/* List of supported bit depths. */
-enum sst_hsw_bitdepth {
-       SST_HSW_DEPTH_8BIT  = 8,
-       SST_HSW_DEPTH_16BIT = 16,
-       SST_HSW_DEPTH_24BIT = 24, /* Default. */
-       SST_HSW_DEPTH_32BIT = 32,
-       SST_HSW_DEPTH_INVALID = 33,
-};
-
-enum sst_hsw_module_id {
-       SST_HSW_MODULE_BASE_FW = 0x0,
-       SST_HSW_MODULE_MP3     = 0x1,
-       SST_HSW_MODULE_AAC_5_1 = 0x2,
-       SST_HSW_MODULE_AAC_2_0 = 0x3,
-       SST_HSW_MODULE_SRC     = 0x4,
-       SST_HSW_MODULE_WAVES   = 0x5,
-       SST_HSW_MODULE_DOLBY   = 0x6,
-       SST_HSW_MODULE_BOOST   = 0x7,
-       SST_HSW_MODULE_LPAL    = 0x8,
-       SST_HSW_MODULE_DTS     = 0x9,
-       SST_HSW_MODULE_PCM_CAPTURE = 0xA,
-       SST_HSW_MODULE_PCM_SYSTEM = 0xB,
-       SST_HSW_MODULE_PCM_REFERENCE = 0xC,
-       SST_HSW_MODULE_PCM = 0xD,
-       SST_HSW_MODULE_BLUETOOTH_RENDER_MODULE = 0xE,
-       SST_HSW_MODULE_BLUETOOTH_CAPTURE_MODULE = 0xF,
-       SST_HSW_MAX_MODULE_ID,
-};
-
-enum sst_hsw_performance_action {
-       SST_HSW_PERF_START = 0,
-       SST_HSW_PERF_STOP = 1,
-};
-
-/* SST firmware module info */
-struct sst_hsw_module_info {
-       u8 name[SST_HSW_MAX_INFO_SIZE];
-       u8 version[SST_HSW_MAX_INFO_SIZE];
-} __attribute__((packed));
-
-/* Module entry point */
-struct sst_hsw_module_entry {
-       enum sst_hsw_module_id module_id;
-       u32 entry_point;
-} __attribute__((packed));
-
-/* Module map - alignement matches DSP */
-struct sst_hsw_module_map {
-       u8 module_entries_count;
-       struct sst_hsw_module_entry module_entries[1];
-} __attribute__((packed));
-
-struct sst_hsw_memory_info {
-       u32 offset;
-       u32 size;
-} __attribute__((packed));
-
-struct sst_hsw_fx_enable {
-       struct sst_hsw_module_map module_map;
-       struct sst_hsw_memory_info persistent_mem;
-} __attribute__((packed));
-
-struct sst_hsw_get_fx_param {
-       u32 parameter_id;
-       u32 param_size;
-} __attribute__((packed));
-
-struct sst_hsw_perf_action {
-       u32 action;
-} __attribute__((packed));
-
-struct sst_hsw_perf_data {
-       u64 timestamp;
-       u64 cycles;
-       u64 datatime;
-} __attribute__((packed));
-
-/* FW version */
-struct sst_hsw_ipc_fw_version {
-       u8 build;
-       u8 minor;
-       u8 major;
-       u8 type;
-       u8 fw_build_hash[SST_HSW_BUILD_HASH_LENGTH];
-       u32 fw_log_providers_hash;
-} __attribute__((packed));
-
-/* Stream ring info */
-struct sst_hsw_ipc_stream_ring {
-       u32 ring_pt_address;
-       u32 num_pages;
-       u32 ring_size;
-       u32 ring_offset;
-       u32 ring_first_pfn;
-} __attribute__((packed));
-
-/* Debug Dump Log Enable Request */
-struct sst_hsw_ipc_debug_log_enable_req {
-       struct sst_hsw_ipc_stream_ring ringinfo;
-       u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
-} __attribute__((packed));
-
-/* Debug Dump Log Reply */
-struct sst_hsw_ipc_debug_log_reply {
-       u32 log_buffer_begining;
-       u32 log_buffer_size;
-} __attribute__((packed));
-
-/* Stream glitch position */
-struct sst_hsw_ipc_stream_glitch_position {
-       u32 glitch_type;
-       u32 present_pos;
-       u32 write_pos;
-} __attribute__((packed));
-
-/* Stream get position */
-struct sst_hsw_ipc_stream_get_position {
-       u32 position;
-       u32 fw_cycle_count;
-} __attribute__((packed));
-
-/* Stream set position */
-struct sst_hsw_ipc_stream_set_position {
-       u32 position;
-       u32 end_of_buffer;
-} __attribute__((packed));
-
-/* Stream Free Request */
-struct sst_hsw_ipc_stream_free_req {
-       u8 stream_id;
-       u8 reserved[3];
-} __attribute__((packed));
-
-/* Set Volume Request */
-struct sst_hsw_ipc_volume_req {
-       u32 channel;
-       u32 target_volume;
-       u64 curve_duration;
-       u32 curve_type;
-} __attribute__((packed));
-
-/* Device Configuration Request */
-struct sst_hsw_ipc_device_config_req {
-       u32 ssp_interface;
-       u32 clock_frequency;
-       u32 mode;
-       u16 clock_divider;
-       u8 channels;
-       u8 reserved;
-} __attribute__((packed));
-
-/* Audio Data formats */
-struct sst_hsw_audio_data_format_ipc {
-       u32 frequency;
-       u32 bitdepth;
-       u32 map;
-       u32 config;
-       u32 style;
-       u8 ch_num;
-       u8 valid_bit;
-       u8 reserved[2];
-} __attribute__((packed));
-
-/* Stream Allocate Request */
-struct sst_hsw_ipc_stream_alloc_req {
-       u8 path_id;
-       u8 stream_type;
-       u8 format_id;
-       u8 reserved;
-       struct sst_hsw_audio_data_format_ipc format;
-       struct sst_hsw_ipc_stream_ring ringinfo;
-       struct sst_hsw_module_map map;
-       struct sst_hsw_memory_info persistent_mem;
-       struct sst_hsw_memory_info scratch_mem;
-       u32 number_of_notifications;
-} __attribute__((packed));
-
-/* Stream Allocate Reply */
-struct sst_hsw_ipc_stream_alloc_reply {
-       u32 stream_hw_id;
-       u32 mixer_hw_id; // returns rate ????
-       u32 read_position_register_address;
-       u32 presentation_position_register_address;
-       u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
-       u32 volume_register_address[SST_HSW_NO_CHANNELS];
-} __attribute__((packed));
-
-/* Get Mixer Stream Info */
-struct sst_hsw_ipc_stream_info_reply {
-       u32 mixer_hw_id;
-       u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
-       u32 volume_register_address[SST_HSW_NO_CHANNELS];
-} __attribute__((packed));
-
-/* DX State Request */
-struct sst_hsw_ipc_dx_req {
-       u8 state;
-       u8 reserved[3];
-} __attribute__((packed));
-
-/* DX State Reply Memory Info Item */
-struct sst_hsw_ipc_dx_memory_item {
-       u32 offset;
-       u32 size;
-       u32 source;
-} __attribute__((packed));
-
-/* DX State Reply */
-struct sst_hsw_ipc_dx_reply {
-       u32 entries_no;
-       struct sst_hsw_ipc_dx_memory_item mem_info[SST_HSW_MAX_DX_REGIONS];
-} __attribute__((packed));
-
-struct sst_hsw_ipc_fw_version;
-
-/* SST Init & Free */
-struct sst_hsw *sst_hsw_new(struct device *dev, const u8 *fw, size_t fw_length,
-       u32 fw_offset);
-void sst_hsw_free(struct sst_hsw *hsw);
-int sst_hsw_fw_get_version(struct sst_hsw *hsw,
-       struct sst_hsw_ipc_fw_version *version);
-u32 create_channel_map(enum sst_hsw_channel_config config);
-
-/* Stream Mixer Controls - */
-int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume);
-int sst_hsw_stream_get_volume(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume);
-
-/* Global Mixer Controls - */
-int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
-       u32 volume);
-int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
-       u32 *volume);
-
-/* Stream API */
-struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
-       u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data),
-       void *data);
-
-int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
-
-/* Stream Configuration */
-int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       enum sst_hsw_stream_path_id path_id,
-       enum sst_hsw_stream_type stream_type,
-       enum sst_hsw_stream_format format_id);
-
-int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 ring_pt_address, u32 num_pages,
-       u32 ring_size, u32 ring_offset, u32 ring_first_pfn);
-
-int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
-
-int sst_hsw_stream_set_valid(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 bits);
-int sst_hsw_stream_set_rate(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       int rate);
-int sst_hsw_stream_set_bits(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       enum sst_hsw_bitdepth bits);
-int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, int channels);
-int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 map,
-       enum sst_hsw_channel_config config);
-int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       enum sst_hsw_interleaving style);
-int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, struct sst_module_runtime *runtime);
-int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 offset, u32 size);
-int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 offset, u32 size);
-snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream);
-void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, snd_pcm_uframes_t val);
-bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream);
-void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, bool val);
-int sst_hsw_mixer_get_info(struct sst_hsw *hsw);
-
-/* Stream ALSA trigger operations */
-int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       int wait);
-int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       int wait);
-int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
-
-/* Stream pointer positions */
-int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 *position);
-int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 *position);
-u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream);
-u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream);
-
-/* HW port config */
-int sst_hsw_device_set_config(struct sst_hsw *hsw,
-       enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
-       enum sst_hsw_device_mode mode, u32 clock_divider);
-
-/* DX Config */
-int sst_hsw_dx_set_state(struct sst_hsw *hsw,
-       enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx);
-
-/* init */
-int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);
-void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata);
-struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
-
-/* runtime module management */
-struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
-       int mod_id, int offset);
-void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime);
-
-/* PM */
-int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw);
-int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw);
-int sst_hsw_dsp_load(struct sst_hsw *hsw);
-int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw);
-
-#endif
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
deleted file mode 100644 (file)
index 7e21e8f..0000000
+++ /dev/null
@@ -1,1277 +0,0 @@
-/*
- * Intel SST Haswell/Broadwell PCM Support
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/dmaengine_pcm.h>
-#include <sound/soc.h>
-#include <sound/tlv.h>
-#include <sound/compress_driver.h>
-
-#include "sst-haswell-ipc.h"
-#include "sst-dsp-priv.h"
-#include "sst-dsp.h"
-
-#define HSW_PCM_COUNT          6
-#define HSW_VOLUME_MAX         0x7FFFFFFF      /* 0dB */
-
-#define SST_OLD_POSITION(d, r, o) ((d) +               \
-                       frames_to_bytes(r, o))
-#define SST_SAMPLES(r, x) (bytes_to_samples(r, \
-                       frames_to_bytes(r, (x))))
-
-/* simple volume table */
-static const u32 volume_map[] = {
-       HSW_VOLUME_MAX >> 30,
-       HSW_VOLUME_MAX >> 29,
-       HSW_VOLUME_MAX >> 28,
-       HSW_VOLUME_MAX >> 27,
-       HSW_VOLUME_MAX >> 26,
-       HSW_VOLUME_MAX >> 25,
-       HSW_VOLUME_MAX >> 24,
-       HSW_VOLUME_MAX >> 23,
-       HSW_VOLUME_MAX >> 22,
-       HSW_VOLUME_MAX >> 21,
-       HSW_VOLUME_MAX >> 20,
-       HSW_VOLUME_MAX >> 19,
-       HSW_VOLUME_MAX >> 18,
-       HSW_VOLUME_MAX >> 17,
-       HSW_VOLUME_MAX >> 16,
-       HSW_VOLUME_MAX >> 15,
-       HSW_VOLUME_MAX >> 14,
-       HSW_VOLUME_MAX >> 13,
-       HSW_VOLUME_MAX >> 12,
-       HSW_VOLUME_MAX >> 11,
-       HSW_VOLUME_MAX >> 10,
-       HSW_VOLUME_MAX >> 9,
-       HSW_VOLUME_MAX >> 8,
-       HSW_VOLUME_MAX >> 7,
-       HSW_VOLUME_MAX >> 6,
-       HSW_VOLUME_MAX >> 5,
-       HSW_VOLUME_MAX >> 4,
-       HSW_VOLUME_MAX >> 3,
-       HSW_VOLUME_MAX >> 2,
-       HSW_VOLUME_MAX >> 1,
-       HSW_VOLUME_MAX >> 0,
-};
-
-#define HSW_PCM_PERIODS_MAX    64
-#define HSW_PCM_PERIODS_MIN    2
-
-#define HSW_PCM_DAI_ID_SYSTEM  0
-#define HSW_PCM_DAI_ID_OFFLOAD0        1
-#define HSW_PCM_DAI_ID_OFFLOAD1        2
-#define HSW_PCM_DAI_ID_LOOPBACK        3
-
-
-static const struct snd_pcm_hardware hsw_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_MMAP |
-                                 SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_INTERLEAVED |
-                                 SNDRV_PCM_INFO_PAUSE |
-                                 SNDRV_PCM_INFO_RESUME |
-                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
-                                 SNDRV_PCM_INFO_DRAIN_TRIGGER,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
-                                 SNDRV_PCM_FMTBIT_S32_LE,
-       .period_bytes_min       = PAGE_SIZE,
-       .period_bytes_max       = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE,
-       .periods_min            = HSW_PCM_PERIODS_MIN,
-       .periods_max            = HSW_PCM_PERIODS_MAX,
-       .buffer_bytes_max       = HSW_PCM_PERIODS_MAX * PAGE_SIZE,
-};
-
-struct hsw_pcm_module_map {
-       int dai_id;
-       int stream;
-       enum sst_hsw_module_id mod_id;
-};
-
-/* private data for each PCM DSP stream */
-struct hsw_pcm_data {
-       int dai_id;
-       struct sst_hsw_stream *stream;
-       struct sst_module_runtime *runtime;
-       struct sst_module_runtime_context context;
-       struct snd_pcm *hsw_pcm;
-       u32 volume[2];
-       struct snd_pcm_substream *substream;
-       struct snd_compr_stream *cstream;
-       unsigned int wpos;
-       struct mutex mutex;
-       bool allocated;
-       int persistent_offset;
-};
-
-enum hsw_pm_state {
-       HSW_PM_STATE_D0 = 0,
-       HSW_PM_STATE_RTD3 = 1,
-       HSW_PM_STATE_D3 = 2,
-};
-
-/* private data for the driver */
-struct hsw_priv_data {
-       /* runtime DSP */
-       struct sst_hsw *hsw;
-       struct device *dev;
-       enum hsw_pm_state pm_state;
-       struct snd_soc_card *soc_card;
-
-       /* page tables */
-       struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
-
-       /* DAI data */
-       struct hsw_pcm_data pcm[HSW_PCM_COUNT][2];
-};
-
-
-/* static mappings between PCMs and modules - may be dynamic in future */
-static struct hsw_pcm_module_map mod_map[] = {
-       {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM},
-       {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM},
-       {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM},
-       {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE},
-       {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE},
-};
-
-static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
-
-static inline u32 hsw_mixer_to_ipc(unsigned int value)
-{
-       if (value >= ARRAY_SIZE(volume_map))
-               return volume_map[0];
-       else
-               return volume_map[value];
-}
-
-static inline unsigned int hsw_ipc_to_mixer(u32 value)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(volume_map); i++) {
-               if (volume_map[i] >= value)
-                       return i;
-       }
-
-       return i - 1;
-}
-
-static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(platform);
-       struct hsw_pcm_data *pcm_data;
-       struct sst_hsw *hsw = pdata->hsw;
-       u32 volume;
-       int dai, stream;
-
-       dai = mod_map[mc->reg].dai_id;
-       stream = mod_map[mc->reg].stream;
-       pcm_data = &pdata->pcm[dai][stream];
-
-       mutex_lock(&pcm_data->mutex);
-       pm_runtime_get_sync(pdata->dev);
-
-       if (!pcm_data->stream) {
-               pcm_data->volume[0] =
-                       hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
-               pcm_data->volume[1] =
-                       hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
-               pm_runtime_mark_last_busy(pdata->dev);
-               pm_runtime_put_autosuspend(pdata->dev);
-               mutex_unlock(&pcm_data->mutex);
-               return 0;
-       }
-
-       if (ucontrol->value.integer.value[0] ==
-               ucontrol->value.integer.value[1]) {
-               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
-               /* apply volume value to all channels */
-               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, SST_HSW_CHANNELS_ALL, volume);
-       } else {
-               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
-               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume);
-               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
-               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume);
-       }
-
-       pm_runtime_mark_last_busy(pdata->dev);
-       pm_runtime_put_autosuspend(pdata->dev);
-       mutex_unlock(&pcm_data->mutex);
-       return 0;
-}
-
-static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(platform);
-       struct hsw_pcm_data *pcm_data;
-       struct sst_hsw *hsw = pdata->hsw;
-       u32 volume;
-       int dai, stream;
-
-       dai = mod_map[mc->reg].dai_id;
-       stream = mod_map[mc->reg].stream;
-       pcm_data = &pdata->pcm[dai][stream];
-
-       mutex_lock(&pcm_data->mutex);
-       pm_runtime_get_sync(pdata->dev);
-
-       if (!pcm_data->stream) {
-               ucontrol->value.integer.value[0] =
-                       hsw_ipc_to_mixer(pcm_data->volume[0]);
-               ucontrol->value.integer.value[1] =
-                       hsw_ipc_to_mixer(pcm_data->volume[1]);
-               pm_runtime_mark_last_busy(pdata->dev);
-               pm_runtime_put_autosuspend(pdata->dev);
-               mutex_unlock(&pcm_data->mutex);
-               return 0;
-       }
-
-       sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 0, &volume);
-       ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
-       sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume);
-       ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
-
-       pm_runtime_mark_last_busy(pdata->dev);
-       pm_runtime_put_autosuspend(pdata->dev);
-       mutex_unlock(&pcm_data->mutex);
-
-       return 0;
-}
-
-static int hsw_volume_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
-       struct sst_hsw *hsw = pdata->hsw;
-       u32 volume;
-
-       pm_runtime_get_sync(pdata->dev);
-
-       if (ucontrol->value.integer.value[0] ==
-               ucontrol->value.integer.value[1]) {
-
-               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
-               sst_hsw_mixer_set_volume(hsw, 0, SST_HSW_CHANNELS_ALL, volume);
-
-       } else {
-               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
-               sst_hsw_mixer_set_volume(hsw, 0, 0, volume);
-
-               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
-               sst_hsw_mixer_set_volume(hsw, 0, 1, volume);
-       }
-
-       pm_runtime_mark_last_busy(pdata->dev);
-       pm_runtime_put_autosuspend(pdata->dev);
-       return 0;
-}
-
-static int hsw_volume_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
-       struct sst_hsw *hsw = pdata->hsw;
-       unsigned int volume = 0;
-
-       pm_runtime_get_sync(pdata->dev);
-       sst_hsw_mixer_get_volume(hsw, 0, 0, &volume);
-       ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
-
-       sst_hsw_mixer_get_volume(hsw, 0, 1, &volume);
-       ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
-
-       pm_runtime_mark_last_busy(pdata->dev);
-       pm_runtime_put_autosuspend(pdata->dev);
-       return 0;
-}
-
-/* TLV used by both global and stream volumes */
-static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
-
-/* System Pin has no volume control */
-static const struct snd_kcontrol_new hsw_volume_controls[] = {
-       /* Global DSP volume */
-       SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8,
-               ARRAY_SIZE(volume_map) - 1, 0,
-               hsw_volume_get, hsw_volume_put, hsw_vol_tlv),
-       /* Offload 0 volume */
-       SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8,
-               ARRAY_SIZE(volume_map) - 1, 0,
-               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
-       /* Offload 1 volume */
-       SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8,
-               ARRAY_SIZE(volume_map) - 1, 0,
-               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
-       /* Mic Capture volume */
-       SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
-               ARRAY_SIZE(volume_map) - 1, 0,
-               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
-};
-
-/* Create DMA buffer page table for DSP */
-static int create_adsp_page_table(struct snd_pcm_substream *substream,
-       struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd,
-       unsigned char *dma_area, size_t size, int pcm)
-{
-       struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
-       int i, pages, stream = substream->stream;
-
-       pages = snd_sgbuf_aligned_pages(size);
-
-       dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
-               dma_area, size, pages);
-
-       for (i = 0; i < pages; i++) {
-               u32 idx = (((i << 2) + i)) >> 1;
-               u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
-               u32 *pg_table;
-
-               dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
-
-               pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx);
-
-               if (i & 1)
-                       *pg_table |= (pfn << 4);
-               else
-                       *pg_table |= pfn;
-       }
-
-       return 0;
-}
-
-/* this may get called several times by oss emulation */
-static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data;
-       struct sst_hsw *hsw = pdata->hsw;
-       struct sst_module *module_data;
-       struct sst_dsp *dsp;
-       struct snd_dma_buffer *dmab;
-       enum sst_hsw_stream_type stream_type;
-       enum sst_hsw_stream_path_id path_id;
-       u32 rate, bits, map, pages, module_id;
-       u8 channels;
-       int ret, dai;
-
-       dai = mod_map[rtd->cpu_dai->id].dai_id;
-       pcm_data = &pdata->pcm[dai][substream->stream];
-
-       /* check if we are being called a subsequent time */
-       if (pcm_data->allocated) {
-               ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
-               if (ret < 0)
-                       dev_dbg(rtd->dev, "error: reset stream failed %d\n",
-                               ret);
-
-               ret = sst_hsw_stream_free(hsw, pcm_data->stream);
-               if (ret < 0) {
-                       dev_dbg(rtd->dev, "error: free stream failed %d\n",
-                               ret);
-                       return ret;
-               }
-               pcm_data->allocated = false;
-
-               pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
-                       hsw_notify_pointer, pcm_data);
-               if (pcm_data->stream == NULL) {
-                       dev_err(rtd->dev, "error: failed to create stream\n");
-                       return -EINVAL;
-               }
-       }
-
-       /* stream direction */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
-       else
-               path_id = SST_HSW_STREAM_PATH_SSP0_IN;
-
-       /* DSP stream type depends on DAI ID */
-       switch (rtd->cpu_dai->id) {
-       case 0:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
-                       module_id = SST_HSW_MODULE_PCM_SYSTEM;
-               }
-               else {
-                       stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
-                       module_id = SST_HSW_MODULE_PCM_CAPTURE;
-               }
-               break;
-       case 1:
-       case 2:
-               stream_type = SST_HSW_STREAM_TYPE_RENDER;
-               module_id = SST_HSW_MODULE_PCM;
-               break;
-       case 3:
-               /* path ID needs to be OUT for loopback */
-               stream_type = SST_HSW_STREAM_TYPE_LOOPBACK;
-               path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
-               module_id = SST_HSW_MODULE_PCM_REFERENCE;
-               break;
-       default:
-               dev_err(rtd->dev, "error: invalid DAI ID %d\n",
-                       rtd->cpu_dai->id);
-               return -EINVAL;
-       };
-
-       ret = sst_hsw_stream_format(hsw, pcm_data->stream,
-               path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT);
-       if (ret < 0) {
-               dev_err(rtd->dev, "error: failed to set format %d\n", ret);
-               return ret;
-       }
-
-       rate = params_rate(params);
-       ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate);
-       if (ret < 0) {
-               dev_err(rtd->dev, "error: could not set rate %d\n", rate);
-               return ret;
-       }
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               bits = SST_HSW_DEPTH_16BIT;
-               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16);
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               bits = SST_HSW_DEPTH_32BIT;
-               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 24);
-               break;
-       case SNDRV_PCM_FORMAT_S8:
-               bits = SST_HSW_DEPTH_8BIT;
-               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 8);
-               break;
-       case SNDRV_PCM_FORMAT_S32_LE:
-               bits = SST_HSW_DEPTH_32BIT;
-               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32);
-               break;
-       default:
-               dev_err(rtd->dev, "error: invalid format %d\n",
-                       params_format(params));
-               return -EINVAL;
-       }
-
-       ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits);
-       if (ret < 0) {
-               dev_err(rtd->dev, "error: could not set bits %d\n", bits);
-               return ret;
-       }
-
-       channels = params_channels(params);
-       map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO);
-       sst_hsw_stream_set_map_config(hsw, pcm_data->stream,
-                       map, SST_HSW_CHANNEL_CONFIG_STEREO);
-
-       ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels);
-       if (ret < 0) {
-               dev_err(rtd->dev, "error: could not set channels %d\n",
-                       channels);
-               return ret;
-       }
-
-       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-       if (ret < 0) {
-               dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n",
-                       params_buffer_bytes(params), ret);
-               return ret;
-       }
-
-       dmab = snd_pcm_get_dma_buf(substream);
-
-       ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area,
-               runtime->dma_bytes, rtd->cpu_dai->id);
-       if (ret < 0)
-               return ret;
-
-       sst_hsw_stream_set_style(hsw, pcm_data->stream,
-               SST_HSW_INTERLEAVING_PER_CHANNEL);
-
-       if (runtime->dma_bytes % PAGE_SIZE)
-               pages = (runtime->dma_bytes / PAGE_SIZE) + 1;
-       else
-               pages = runtime->dma_bytes / PAGE_SIZE;
-
-       ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
-               pdata->dmab[rtd->cpu_dai->id][substream->stream].addr,
-               pages, runtime->dma_bytes, 0,
-               snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT);
-       if (ret < 0) {
-               dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
-               return ret;
-       }
-
-       dsp = sst_hsw_get_dsp(hsw);
-
-       module_data = sst_module_get_from_id(dsp, module_id);
-       if (module_data == NULL) {
-               dev_err(rtd->dev, "error: failed to get module config\n");
-               return -EINVAL;
-       }
-
-       sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
-               pcm_data->runtime);
-
-       ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
-       if (ret < 0) {
-               dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
-               return ret;
-       }
-
-       if (!pcm_data->allocated) {
-               /* Set previous saved volume */
-               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
-                               0, pcm_data->volume[0]);
-               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
-                               1, pcm_data->volume[1]);
-               pcm_data->allocated = true;
-       }
-
-       ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
-       if (ret < 0)
-               dev_err(rtd->dev, "error: failed to pause %d\n", ret);
-
-       return 0;
-}
-
-static int hsw_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       snd_pcm_lib_free_pages(substream);
-       return 0;
-}
-
-static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data;
-       struct sst_hsw_stream *sst_stream;
-       struct sst_hsw *hsw = pdata->hsw;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       snd_pcm_uframes_t pos;
-       int dai;
-
-       dai = mod_map[rtd->cpu_dai->id].dai_id;
-       pcm_data = &pdata->pcm[dai][substream->stream];
-       sst_stream = pcm_data->stream;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               sst_hsw_stream_set_silence_start(hsw, sst_stream, false);
-               sst_hsw_stream_resume(hsw, pcm_data->stream, 0);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               sst_hsw_stream_set_silence_start(hsw, sst_stream, false);
-               sst_hsw_stream_pause(hsw, pcm_data->stream, 0);
-               break;
-       case SNDRV_PCM_TRIGGER_DRAIN:
-               pos = runtime->control->appl_ptr % runtime->buffer_size;
-               sst_hsw_stream_set_old_position(hsw, pcm_data->stream, pos);
-               sst_hsw_stream_set_silence_start(hsw, sst_stream, true);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
-{
-       struct hsw_pcm_data *pcm_data = data;
-       struct snd_pcm_substream *substream = pcm_data->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct sst_hsw *hsw = pdata->hsw;
-       u32 pos;
-       snd_pcm_uframes_t position = bytes_to_frames(runtime,
-                sst_hsw_get_dsp_position(hsw, pcm_data->stream));
-       unsigned char *dma_area = runtime->dma_area;
-       snd_pcm_uframes_t dma_frames =
-               bytes_to_frames(runtime, runtime->dma_bytes);
-       snd_pcm_uframes_t old_position;
-       ssize_t samples;
-
-       pos = frames_to_bytes(runtime,
-               (runtime->control->appl_ptr % runtime->buffer_size));
-
-       dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
-
-       /* SST fw don't know where to stop dma
-        * So, SST driver need to clean the data which has been consumed
-        */
-       if (dma_area == NULL || dma_frames <= 0
-               || (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-               || !sst_hsw_stream_get_silence_start(hsw, stream)) {
-               snd_pcm_period_elapsed(substream);
-               return pos;
-       }
-
-       old_position = sst_hsw_stream_get_old_position(hsw, stream);
-       if (position > old_position) {
-               if (position < dma_frames) {
-                       samples = SST_SAMPLES(runtime, position - old_position);
-                       snd_pcm_format_set_silence(runtime->format,
-                               SST_OLD_POSITION(dma_area,
-                                       runtime, old_position),
-                               samples);
-               } else
-                       dev_err(rtd->dev, "PCM: position is wrong\n");
-       } else {
-               if (old_position < dma_frames) {
-                       samples = SST_SAMPLES(runtime,
-                               dma_frames - old_position);
-                       snd_pcm_format_set_silence(runtime->format,
-                               SST_OLD_POSITION(dma_area,
-                                       runtime, old_position),
-                               samples);
-               } else
-                       dev_err(rtd->dev, "PCM: dma_bytes is wrong\n");
-               if (position < dma_frames) {
-                       samples = SST_SAMPLES(runtime, position);
-                       snd_pcm_format_set_silence(runtime->format,
-                               dma_area, samples);
-               } else
-                       dev_err(rtd->dev, "PCM: position is wrong\n");
-       }
-       sst_hsw_stream_set_old_position(hsw, stream, position);
-
-       /* let alsa know we have play a period */
-       snd_pcm_period_elapsed(substream);
-       return pos;
-}
-
-static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data;
-       struct sst_hsw *hsw = pdata->hsw;
-       snd_pcm_uframes_t offset;
-       uint64_t ppos;
-       u32 position;
-       int dai;
-
-       dai = mod_map[rtd->cpu_dai->id].dai_id;
-       pcm_data = &pdata->pcm[dai][substream->stream];
-       position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
-
-       offset = bytes_to_frames(runtime, position);
-       ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
-
-       dev_vdbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
-               position, ppos);
-       return offset;
-}
-
-static int hsw_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data;
-       struct sst_hsw *hsw = pdata->hsw;
-       int dai;
-
-       dai = mod_map[rtd->cpu_dai->id].dai_id;
-       pcm_data = &pdata->pcm[dai][substream->stream];
-
-       mutex_lock(&pcm_data->mutex);
-       pm_runtime_get_sync(pdata->dev);
-
-       snd_soc_pcm_set_drvdata(rtd, pcm_data);
-       pcm_data->substream = substream;
-
-       snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware);
-
-       pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
-               hsw_notify_pointer, pcm_data);
-       if (pcm_data->stream == NULL) {
-               dev_err(rtd->dev, "error: failed to create stream\n");
-               pm_runtime_mark_last_busy(pdata->dev);
-               pm_runtime_put_autosuspend(pdata->dev);
-               mutex_unlock(&pcm_data->mutex);
-               return -EINVAL;
-       }
-
-       mutex_unlock(&pcm_data->mutex);
-       return 0;
-}
-
-static int hsw_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data;
-       struct sst_hsw *hsw = pdata->hsw;
-       int ret, dai;
-
-       dai = mod_map[rtd->cpu_dai->id].dai_id;
-       pcm_data = &pdata->pcm[dai][substream->stream];
-
-       mutex_lock(&pcm_data->mutex);
-       ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
-       if (ret < 0) {
-               dev_dbg(rtd->dev, "error: reset stream failed %d\n", ret);
-               goto out;
-       }
-
-       ret = sst_hsw_stream_free(hsw, pcm_data->stream);
-       if (ret < 0) {
-               dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
-               goto out;
-       }
-       pcm_data->allocated = 0;
-       pcm_data->stream = NULL;
-
-out:
-       pm_runtime_mark_last_busy(pdata->dev);
-       pm_runtime_put_autosuspend(pdata->dev);
-       mutex_unlock(&pcm_data->mutex);
-       return ret;
-}
-
-static struct snd_pcm_ops hsw_pcm_ops = {
-       .open           = hsw_pcm_open,
-       .close          = hsw_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = hsw_pcm_hw_params,
-       .hw_free        = hsw_pcm_hw_free,
-       .trigger        = hsw_pcm_trigger,
-       .pointer        = hsw_pcm_pointer,
-       .page           = snd_pcm_sgbuf_ops_page,
-};
-
-static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
-{
-       struct sst_hsw *hsw = pdata->hsw;
-       struct hsw_pcm_data *pcm_data;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
-
-               /* create new runtime module, use same offset if recreated */
-               pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
-                       mod_map[i].mod_id, pcm_data->persistent_offset);
-               if (pcm_data->runtime == NULL)
-                       goto err;
-               pcm_data->persistent_offset =
-                       pcm_data->runtime->persistent_offset;
-       }
-
-       return 0;
-
-err:
-       for (--i; i >= 0; i--) {
-               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
-               sst_hsw_runtime_module_free(pcm_data->runtime);
-       }
-
-       return -ENODEV;
-}
-
-static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
-{
-       struct hsw_pcm_data *pcm_data;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
-
-               sst_hsw_runtime_module_free(pcm_data->runtime);
-       }
-}
-
-static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_pcm *pcm = rtd->pcm;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
-       struct hsw_priv_data *priv_data = dev_get_drvdata(platform->dev);
-       struct device *dev = pdata->dma_dev;
-       int ret = 0;
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
-                       pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
-                       SNDRV_DMA_TYPE_DEV_SG,
-                       dev,
-                       hsw_pcm_hardware.buffer_bytes_max,
-                       hsw_pcm_hardware.buffer_bytes_max);
-               if (ret) {
-                       dev_err(rtd->dev, "dma buffer allocation failed %d\n",
-                               ret);
-                       return ret;
-               }
-       }
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
-               priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm;
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
-               priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm;
-
-       return ret;
-}
-
-#define HSW_FORMATS \
-       (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
-
-static struct snd_soc_dai_driver hsw_dais[] = {
-       {
-               .name  = "System Pin",
-               .id = HSW_PCM_DAI_ID_SYSTEM,
-               .playback = {
-                       .stream_name = "System Playback",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
-               },
-               .capture = {
-                       .stream_name = "Analog Capture",
-                       .channels_min = 2,
-                       .channels_max = 4,
-                       .rates = SNDRV_PCM_RATE_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
-               },
-       },
-       {
-               /* PCM */
-               .name  = "Offload0 Pin",
-               .id = HSW_PCM_DAI_ID_OFFLOAD0,
-               .playback = {
-                       .stream_name = "Offload0 Playback",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_8000_192000,
-                       .formats = HSW_FORMATS,
-               },
-       },
-       {
-               /* PCM */
-               .name  = "Offload1 Pin",
-               .id = HSW_PCM_DAI_ID_OFFLOAD1,
-               .playback = {
-                       .stream_name = "Offload1 Playback",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_8000_192000,
-                       .formats = HSW_FORMATS,
-               },
-       },
-       {
-               .name  = "Loopback Pin",
-               .id = HSW_PCM_DAI_ID_LOOPBACK,
-               .capture = {
-                       .stream_name = "Loopback Capture",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
-               },
-       },
-};
-
-static const struct snd_soc_dapm_widget widgets[] = {
-
-       /* Backend DAIs  */
-       SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
-
-       /* Global Playback Mixer */
-       SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
-};
-
-static const struct snd_soc_dapm_route graph[] = {
-
-       /* Playback Mixer */
-       {"Playback VMixer", NULL, "System Playback"},
-       {"Playback VMixer", NULL, "Offload0 Playback"},
-       {"Playback VMixer", NULL, "Offload1 Playback"},
-
-       {"SSP0 CODEC OUT", NULL, "Playback VMixer"},
-
-       {"Analog Capture", NULL, "SSP0 CODEC IN"},
-};
-
-static int hsw_pcm_probe(struct snd_soc_platform *platform)
-{
-       struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform);
-       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
-       struct device *dma_dev, *dev;
-       int i, ret = 0;
-
-       if (!pdata)
-               return -ENODEV;
-
-       dev = platform->dev;
-       dma_dev = pdata->dma_dev;
-
-       priv_data->hsw = pdata->dsp;
-       priv_data->dev = platform->dev;
-       priv_data->pm_state = HSW_PM_STATE_D0;
-       priv_data->soc_card = platform->component.card;
-
-       /* allocate DSP buffer page tables */
-       for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
-
-               /* playback */
-               if (hsw_dais[i].playback.channels_min) {
-                       mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_PLAYBACK].mutex);
-                       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
-                               PAGE_SIZE, &priv_data->dmab[i][0]);
-                       if (ret < 0)
-                               goto err;
-               }
-
-               /* capture */
-               if (hsw_dais[i].capture.channels_min) {
-                       mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_CAPTURE].mutex);
-                       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
-                               PAGE_SIZE, &priv_data->dmab[i][1]);
-                       if (ret < 0)
-                               goto err;
-               }
-       }
-
-       /* allocate runtime modules */
-       hsw_pcm_create_modules(priv_data);
-
-       /* enable runtime PM with auto suspend */
-       pm_runtime_set_autosuspend_delay(platform->dev,
-               SST_RUNTIME_SUSPEND_DELAY);
-       pm_runtime_use_autosuspend(platform->dev);
-       pm_runtime_enable(platform->dev);
-       pm_runtime_idle(platform->dev);
-
-       return 0;
-
-err:
-       for (;i >= 0; i--) {
-               if (hsw_dais[i].playback.channels_min)
-                       snd_dma_free_pages(&priv_data->dmab[i][0]);
-               if (hsw_dais[i].capture.channels_min)
-                       snd_dma_free_pages(&priv_data->dmab[i][1]);
-       }
-       return ret;
-}
-
-static int hsw_pcm_remove(struct snd_soc_platform *platform)
-{
-       struct hsw_priv_data *priv_data =
-               snd_soc_platform_get_drvdata(platform);
-       int i;
-
-       pm_runtime_disable(platform->dev);
-       hsw_pcm_free_modules(priv_data);
-
-       for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
-               if (hsw_dais[i].playback.channels_min)
-                       snd_dma_free_pages(&priv_data->dmab[i][0]);
-               if (hsw_dais[i].capture.channels_min)
-                       snd_dma_free_pages(&priv_data->dmab[i][1]);
-       }
-
-       return 0;
-}
-
-static struct snd_soc_platform_driver hsw_soc_platform = {
-       .probe          = hsw_pcm_probe,
-       .remove         = hsw_pcm_remove,
-       .ops            = &hsw_pcm_ops,
-       .pcm_new        = hsw_pcm_new,
-};
-
-static const struct snd_soc_component_driver hsw_dai_component = {
-       .name = "haswell-dai",
-       .controls = hsw_volume_controls,
-       .num_controls = ARRAY_SIZE(hsw_volume_controls),
-       .dapm_widgets = widgets,
-       .num_dapm_widgets = ARRAY_SIZE(widgets),
-       .dapm_routes = graph,
-       .num_dapm_routes = ARRAY_SIZE(graph),
-};
-
-static int hsw_pcm_dev_probe(struct platform_device *pdev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
-       struct hsw_priv_data *priv_data;
-       int ret;
-
-       if (!sst_pdata)
-               return -EINVAL;
-
-       priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL);
-       if (!priv_data)
-               return -ENOMEM;
-
-       ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
-       if (ret < 0)
-               return -ENODEV;
-
-       priv_data->hsw = sst_pdata->dsp;
-       platform_set_drvdata(pdev, priv_data);
-
-       ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
-       if (ret < 0)
-               goto err_plat;
-
-       ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component,
-               hsw_dais, ARRAY_SIZE(hsw_dais));
-       if (ret < 0)
-               goto err_comp;
-
-       return 0;
-
-err_comp:
-       snd_soc_unregister_platform(&pdev->dev);
-err_plat:
-       sst_hsw_dsp_free(&pdev->dev, sst_pdata);
-       return 0;
-}
-
-static int hsw_pcm_dev_remove(struct platform_device *pdev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
-
-       snd_soc_unregister_platform(&pdev->dev);
-       snd_soc_unregister_component(&pdev->dev);
-       sst_hsw_dsp_free(&pdev->dev, sst_pdata);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-
-static int hsw_pcm_runtime_idle(struct device *dev)
-{
-       return 0;
-}
-
-static int hsw_pcm_runtime_suspend(struct device *dev)
-{
-       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
-       struct sst_hsw *hsw = pdata->hsw;
-
-       if (pdata->pm_state >= HSW_PM_STATE_RTD3)
-               return 0;
-
-       sst_hsw_dsp_runtime_suspend(hsw);
-       sst_hsw_dsp_runtime_sleep(hsw);
-       pdata->pm_state = HSW_PM_STATE_RTD3;
-
-       return 0;
-}
-
-static int hsw_pcm_runtime_resume(struct device *dev)
-{
-       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
-       struct sst_hsw *hsw = pdata->hsw;
-       int ret;
-
-       if (pdata->pm_state != HSW_PM_STATE_RTD3)
-               return 0;
-
-       ret = sst_hsw_dsp_load(hsw);
-       if (ret < 0) {
-               dev_err(dev, "failed to reload %d\n", ret);
-               return ret;
-       }
-
-       ret = hsw_pcm_create_modules(pdata);
-       if (ret < 0) {
-               dev_err(dev, "failed to create modules %d\n", ret);
-               return ret;
-       }
-
-       ret = sst_hsw_dsp_runtime_resume(hsw);
-       if (ret < 0)
-               return ret;
-       else if (ret == 1) /* no action required */
-               return 0;
-
-       pdata->pm_state = HSW_PM_STATE_D0;
-       return ret;
-}
-
-#else
-#define hsw_pcm_runtime_idle           NULL
-#define hsw_pcm_runtime_suspend                NULL
-#define hsw_pcm_runtime_resume         NULL
-#endif
-
-#ifdef CONFIG_PM
-
-static void hsw_pcm_complete(struct device *dev)
-{
-       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
-       struct sst_hsw *hsw = pdata->hsw;
-       struct hsw_pcm_data *pcm_data;
-       int i, err;
-
-       if (pdata->pm_state != HSW_PM_STATE_D3)
-               return;
-
-       err = sst_hsw_dsp_load(hsw);
-       if (err < 0) {
-               dev_err(dev, "failed to reload %d\n", err);
-               return;
-       }
-
-       err = hsw_pcm_create_modules(pdata);
-       if (err < 0) {
-               dev_err(dev, "failed to create modules %d\n", err);
-               return;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
-
-               if (!pcm_data->substream)
-                       continue;
-
-               err = sst_module_runtime_restore(pcm_data->runtime,
-                       &pcm_data->context);
-               if (err < 0)
-                       dev_err(dev, "failed to restore context for PCM %d\n", i);
-       }
-
-       snd_soc_resume(pdata->soc_card->dev);
-
-       err = sst_hsw_dsp_runtime_resume(hsw);
-       if (err < 0)
-               return;
-       else if (err == 1) /* no action required */
-               return;
-
-       pdata->pm_state = HSW_PM_STATE_D0;
-       return;
-}
-
-static int hsw_pcm_prepare(struct device *dev)
-{
-       struct hsw_priv_data *pdata = dev_get_drvdata(dev);
-       struct sst_hsw *hsw = pdata->hsw;
-       struct hsw_pcm_data *pcm_data;
-       int i, err;
-
-       if (pdata->pm_state == HSW_PM_STATE_D3)
-               return 0;
-       else if (pdata->pm_state == HSW_PM_STATE_D0) {
-               /* suspend all active streams */
-               for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-                       pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
-
-                       if (!pcm_data->substream)
-                               continue;
-                       dev_dbg(dev, "suspending pcm %d\n", i);
-                       snd_pcm_suspend_all(pcm_data->hsw_pcm);
-
-                       /* We need to wait until the DSP FW stops the streams */
-                       msleep(2);
-               }
-
-               /* preserve persistent memory */
-               for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-                       pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
-
-                       if (!pcm_data->substream)
-                               continue;
-
-                       dev_dbg(dev, "saving context pcm %d\n", i);
-                       err = sst_module_runtime_save(pcm_data->runtime,
-                               &pcm_data->context);
-                       if (err < 0)
-                               dev_err(dev, "failed to save context for PCM %d\n", i);
-               }
-               /* enter D3 state and stall */
-               sst_hsw_dsp_runtime_suspend(hsw);
-               /* put the DSP to sleep */
-               sst_hsw_dsp_runtime_sleep(hsw);
-       }
-
-       snd_soc_suspend(pdata->soc_card->dev);
-       snd_soc_poweroff(pdata->soc_card->dev);
-
-       pdata->pm_state = HSW_PM_STATE_D3;
-
-       return 0;
-}
-
-#else
-#define hsw_pcm_prepare                NULL
-#define hsw_pcm_complete       NULL
-#endif
-
-static const struct dev_pm_ops hsw_pcm_pm = {
-       .runtime_idle = hsw_pcm_runtime_idle,
-       .runtime_suspend = hsw_pcm_runtime_suspend,
-       .runtime_resume = hsw_pcm_runtime_resume,
-       .prepare = hsw_pcm_prepare,
-       .complete = hsw_pcm_complete,
-};
-
-static struct platform_driver hsw_pcm_driver = {
-       .driver = {
-               .name = "haswell-pcm-audio",
-               .pm = &hsw_pcm_pm,
-       },
-
-       .probe = hsw_pcm_dev_probe,
-       .remove = hsw_pcm_dev_remove,
-};
-module_platform_driver(hsw_pcm_driver);
-
-MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
-MODULE_DESCRIPTION("Haswell/Lynxpoint + Broadwell/Wildcatpoint PCM");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:haswell-pcm-audio");
diff --git a/sound/soc/intel/sst-mfld-dsp.h b/sound/soc/intel/sst-mfld-dsp.h
deleted file mode 100644 (file)
index 4257263..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-#ifndef __SST_MFLD_DSP_H__
-#define __SST_MFLD_DSP_H__
-/*
- *  sst_mfld_dsp.h - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-14 Intel Corporation
- *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#define SST_MAX_BIN_BYTES 1024
-
-#define MAX_DBG_RW_BYTES 80
-#define MAX_NUM_SCATTER_BUFFERS 8
-#define MAX_LOOP_BACK_DWORDS 8
-/* IPC base address and mailbox, timestamp offsets */
-#define SST_MAILBOX_SIZE 0x0400
-#define SST_MAILBOX_SEND 0x0000
-#define SST_TIME_STAMP 0x1800
-#define SST_TIME_STAMP_MRFLD 0x800
-#define SST_RESERVED_OFFSET 0x1A00
-#define SST_SCU_LPE_MAILBOX 0x1000
-#define SST_LPE_SCU_MAILBOX 0x1400
-#define SST_SCU_LPE_LOG_BUF (SST_SCU_LPE_MAILBOX+16)
-#define PROCESS_MSG 0x80
-
-/* Message ID's for IPC messages */
-/* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */
-
-/* I2L Firmware/Codec Download msgs */
-#define IPC_IA_PREP_LIB_DNLD 0x01
-#define IPC_IA_LIB_DNLD_CMPLT 0x02
-#define IPC_IA_GET_FW_VERSION 0x04
-#define IPC_IA_GET_FW_BUILD_INF 0x05
-#define IPC_IA_GET_FW_INFO 0x06
-#define IPC_IA_GET_FW_CTXT 0x07
-#define IPC_IA_SET_FW_CTXT 0x08
-#define IPC_IA_PREPARE_SHUTDOWN 0x31
-/* I2L Codec Config/control msgs */
-#define IPC_PREP_D3 0x10
-#define IPC_IA_SET_CODEC_PARAMS 0x10
-#define IPC_IA_GET_CODEC_PARAMS 0x11
-#define IPC_IA_SET_PPP_PARAMS 0x12
-#define IPC_IA_GET_PPP_PARAMS 0x13
-#define IPC_SST_PERIOD_ELAPSED_MRFLD 0xA
-#define IPC_IA_ALG_PARAMS 0x1A
-#define IPC_IA_TUNING_PARAMS 0x1B
-#define IPC_IA_SET_RUNTIME_PARAMS 0x1C
-#define IPC_IA_SET_PARAMS 0x1
-#define IPC_IA_GET_PARAMS 0x2
-
-#define IPC_EFFECTS_CREATE 0xE
-#define IPC_EFFECTS_DESTROY 0xF
-
-/* I2L Stream config/control msgs */
-#define IPC_IA_ALLOC_STREAM_MRFLD 0x2
-#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */
-#define IPC_IA_FREE_STREAM_MRFLD 0x03
-#define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */
-#define IPC_IA_SET_STREAM_PARAMS 0x22
-#define IPC_IA_SET_STREAM_PARAMS_MRFLD 0x12
-#define IPC_IA_GET_STREAM_PARAMS 0x23
-#define IPC_IA_PAUSE_STREAM 0x24
-#define IPC_IA_PAUSE_STREAM_MRFLD 0x4
-#define IPC_IA_RESUME_STREAM 0x25
-#define IPC_IA_RESUME_STREAM_MRFLD 0x5
-#define IPC_IA_DROP_STREAM 0x26
-#define IPC_IA_DROP_STREAM_MRFLD 0x07
-#define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */
-#define IPC_IA_DRAIN_STREAM_MRFLD 0x8
-#define IPC_IA_CONTROL_ROUTING 0x29
-#define IPC_IA_VTSV_UPDATE_MODULES 0x20
-#define IPC_IA_VTSV_DETECTED 0x21
-
-#define IPC_IA_START_STREAM_MRFLD 0X06
-#define IPC_IA_START_STREAM 0x30 /* Short msg with str_id */
-
-#define IPC_IA_SET_GAIN_MRFLD 0x21
-/* Debug msgs */
-#define IPC_IA_DBG_MEM_READ 0x40
-#define IPC_IA_DBG_MEM_WRITE 0x41
-#define IPC_IA_DBG_LOOP_BACK 0x42
-#define IPC_IA_DBG_LOG_ENABLE 0x45
-#define IPC_IA_DBG_SET_PROBE_PARAMS 0x47
-
-/* L2I Firmware/Codec Download msgs */
-#define IPC_IA_FW_INIT_CMPLT 0x81
-#define IPC_IA_FW_INIT_CMPLT_MRFLD 0x01
-#define IPC_IA_FW_ASYNC_ERR_MRFLD 0x11
-
-/* L2I Codec Config/control msgs */
-#define IPC_SST_FRAGMENT_ELPASED 0x90 /* Request IA more data */
-
-#define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */
-#define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */
-#define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */
-#define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */
-#define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/* error in processing a stream */
-#define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */
-
-#define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occurred */
-/* L2S messages */
-#define IPC_SC_DDR_LINK_UP 0xC0
-#define IPC_SC_DDR_LINK_DOWN 0xC1
-#define IPC_SC_SET_LPECLK_REQ 0xC2
-#define IPC_SC_SSP_BIT_BANG 0xC3
-
-/* L2I Error reporting msgs */
-#define IPC_IA_MEM_ALLOC_FAIL 0xE0
-#define IPC_IA_PROC_ERR 0xE1 /* error in processing a
-                                       stream can be used by playback and
-                                       capture modules */
-
-/* L2I Debug msgs */
-#define IPC_IA_PRINT_STRING 0xF0
-
-/* Buffer under-run */
-#define IPC_IA_BUF_UNDER_RUN_MRFLD 0x0B
-
-/* Mrfld specific defines:
- * For asynchronous messages(INIT_CMPLT, PERIOD_ELAPSED, ASYNC_ERROR)
- * received from FW, the format is:
- *  - IPC High: pvt_id is set to zero. Always short message.
- *  - msg_id is in lower 16-bits of IPC low payload.
- *  - pipe_id is in higher 16-bits of IPC low payload for period_elapsed.
- *  - error id is in higher 16-bits of IPC low payload for async errors.
- */
-#define SST_ASYNC_DRV_ID 0
-
-/* Command Response or Acknowledge message to any IPC message will have
- * same message ID and stream ID information which is sent.
- * There is no specific Ack message ID. The data field is used as response
- * meaning.
- */
-enum ackData {
-       IPC_ACK_SUCCESS = 0,
-       IPC_ACK_FAILURE,
-};
-
-enum ipc_ia_msg_id {
-       IPC_CMD = 1,            /*!< Task Control message ID */
-       IPC_SET_PARAMS = 2,/*!< Task Set param message ID */
-       IPC_GET_PARAMS = 3,     /*!< Task Get param message ID */
-       IPC_INVALID = 0xFF,     /*!<Task Get param message ID */
-};
-
-enum sst_codec_types {
-       /*  AUDIO/MUSIC CODEC Type Definitions */
-       SST_CODEC_TYPE_UNKNOWN = 0,
-       SST_CODEC_TYPE_PCM,     /* Pass through Audio codec */
-       SST_CODEC_TYPE_MP3,
-       SST_CODEC_TYPE_MP24,
-       SST_CODEC_TYPE_AAC,
-       SST_CODEC_TYPE_AACP,
-       SST_CODEC_TYPE_eAACP,
-};
-
-enum stream_type {
-       SST_STREAM_TYPE_NONE = 0,
-       SST_STREAM_TYPE_MUSIC = 1,
-};
-
-enum sst_error_codes {
-       /* Error code,response to msgId: Description */
-       /* Common error codes */
-       SST_SUCCESS = 0,        /* Success */
-       SST_ERR_INVALID_STREAM_ID = 1,
-       SST_ERR_INVALID_MSG_ID = 2,
-       SST_ERR_INVALID_STREAM_OP = 3,
-       SST_ERR_INVALID_PARAMS = 4,
-       SST_ERR_INVALID_CODEC = 5,
-       SST_ERR_INVALID_MEDIA_TYPE = 6,
-       SST_ERR_STREAM_ERR = 7,
-
-       SST_ERR_STREAM_IN_USE = 15,
-};
-
-struct ipc_dsp_hdr {
-       u16 mod_index_id:8;             /*!< DSP Command ID specific to tasks */
-       u16 pipe_id:8;  /*!< instance of the module in the pipeline */
-       u16 mod_id;             /*!< Pipe_id */
-       u16 cmd_id;             /*!< Module ID = lpe_algo_types_t */
-       u16 length;             /*!< Length of the payload only */
-} __packed;
-
-union ipc_header_high {
-       struct {
-               u32  msg_id:8;      /* Message ID - Max 256 Message Types */
-               u32  task_id:4;     /* Task ID associated with this comand */
-               u32  drv_id:4;    /* Identifier for the driver to track*/
-               u32  rsvd1:8;       /* Reserved */
-               u32  result:4;      /* Reserved */
-               u32  res_rqd:1;     /* Response rqd */
-               u32  large:1;       /* Large Message if large = 1 */
-               u32  done:1;        /* bit 30 - Done bit */
-               u32  busy:1;        /* bit 31 - busy bit*/
-       } part;
-       u32 full;
-} __packed;
-/* IPC header */
-union ipc_header_mrfld {
-       struct {
-               u32 header_low_payload;
-               union ipc_header_high header_high;
-       } p;
-       u64 full;
-} __packed;
-/* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/
-
-/* IPC Header */
-union ipc_header {
-       struct {
-               u32  msg_id:8; /* Message ID - Max 256 Message Types */
-               u32  str_id:5;
-               u32  large:1;   /* Large Message if large = 1 */
-               u32  reserved:2;        /* Reserved for future use */
-               u32  data:14;   /* Ack/Info for msg, size of msg in Mailbox */
-               u32  done:1; /* bit 30 */
-               u32  busy:1; /* bit 31 */
-       } part;
-       u32 full;
-} __packed;
-
-/* Firmware build info */
-struct sst_fw_build_info {
-       unsigned char  date[16]; /* Firmware build date */
-       unsigned char  time[16]; /* Firmware build time */
-} __packed;
-
-/* Firmware Version info */
-struct snd_sst_fw_version {
-       u8 build;       /* build number*/
-       u8 minor;       /* minor number*/
-       u8 major;       /* major number*/
-       u8 type;        /* build type */
-};
-
-struct ipc_header_fw_init {
-       struct snd_sst_fw_version fw_version;/* Firmware version details */
-       struct sst_fw_build_info build_info;
-       u16 result;     /* Fw init result */
-       u8 module_id; /* Module ID in case of error */
-       u8 debug_info; /* Debug info from Module ID in case of fail */
-} __packed;
-
-struct snd_sst_tstamp {
-       u64 ring_buffer_counter;        /* PB/CP: Bytes copied from/to DDR. */
-       u64 hardware_counter;       /* PB/CP: Bytes DMAed to/from SSP. */
-       u64 frames_decoded;
-       u64 bytes_decoded;
-       u64 bytes_copied;
-       u32 sampling_frequency;
-       u32 channel_peak[8];
-} __packed;
-
-/* Stream type params struture for Alloc stream */
-struct snd_sst_str_type {
-       u8 codec_type;          /* Codec type */
-       u8 str_type;            /* 1 = voice 2 = music */
-       u8 operation;           /* Playback or Capture */
-       u8 protected_str;       /* 0=Non DRM, 1=DRM */
-       u8 time_slots;
-       u8 reserved;            /* Reserved */
-       u16 result;             /* Result used for acknowledgment */
-} __packed;
-
-/* Library info structure */
-struct module_info {
-       u32 lib_version;
-       u32 lib_type;/*TBD- KLOCKWORK u8 lib_type;*/
-       u32 media_type;
-       u8  lib_name[12];
-       u32 lib_caps;
-       unsigned char  b_date[16]; /* Lib build date */
-       unsigned char  b_time[16]; /* Lib build time */
-} __packed;
-
-/* Library slot info */
-struct lib_slot_info {
-       u8  slot_num; /* 1 or 2 */
-       u8  reserved1;
-       u16 reserved2;
-       u32 iram_size; /* slot size in IRAM */
-       u32 dram_size; /* slot size in DRAM */
-       u32 iram_offset; /* starting offset of slot in IRAM */
-       u32 dram_offset; /* starting offset of slot in DRAM */
-} __packed;
-
-struct snd_ppp_mixer_params {
-       __u32                   type; /*Type of the parameter */
-       __u32                   size;
-       __u32                   input_stream_bitmap; /*Input stream Bit Map*/
-} __packed;
-
-struct snd_sst_lib_download {
-       struct module_info lib_info; /* library info type, capabilities etc */
-       struct lib_slot_info slot_info; /* slot info to be downloaded */
-       u32 mod_entry_pt;
-};
-
-struct snd_sst_lib_download_info {
-       struct snd_sst_lib_download dload_lib;
-       u16 result;     /* Result used for acknowledgment */
-       u8 pvt_id; /* Private ID */
-       u8 reserved;  /* for alignment */
-};
-struct snd_pcm_params {
-       u8 num_chan;    /* 1=Mono, 2=Stereo */
-       u8 pcm_wd_sz;   /* 16/24 - bit*/
-       u8 use_offload_path;    /* 0-PCM using period elpased & ALSA interfaces
-                                  1-PCM stream via compressed interface  */
-       u8 reserved2;
-       u32 sfreq;    /* Sampling rate in Hz */
-       u8 channel_map[8];
-} __packed;
-
-/* MP3 Music Parameters Message */
-struct snd_mp3_params {
-       u8  num_chan;   /* 1=Mono, 2=Stereo     */
-       u8  pcm_wd_sz; /* 16/24 - bit*/
-       u8  crc_check; /* crc_check - disable (0) or enable (1) */
-       u8  reserved1; /* unused*/
-       u16 reserved2;  /* Unused */
-} __packed;
-
-#define AAC_BIT_STREAM_ADTS            0
-#define AAC_BIT_STREAM_ADIF            1
-#define AAC_BIT_STREAM_RAW             2
-
-/* AAC Music Parameters Message */
-struct snd_aac_params {
-       u8 num_chan; /* 1=Mono, 2=Stereo*/
-       u8 pcm_wd_sz; /* 16/24 - bit*/
-       u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */
-       u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
-       u16  reser2;
-       u32 externalsr; /*sampling rate of basic AAC raw bit stream*/
-       u8 sbr_signalling;/*disable/enable/set automode the SBR tool.AAC+*/
-       u8 reser1;
-       u16  reser3;
-} __packed;
-
-/* WMA Music Parameters Message */
-struct snd_wma_params {
-       u8  num_chan;   /* 1=Mono, 2=Stereo */
-       u8  pcm_wd_sz;  /* 16/24 - bit*/
-       u16 reserved1;
-       u32 brate;      /* Use the hard coded value. */
-       u32 sfreq;      /* Sampling freq eg. 8000, 441000, 48000 */
-       u32 channel_mask;  /* Channel Mask */
-       u16 format_tag; /* Format Tag */
-       u16 block_align;        /* packet size */
-       u16 wma_encode_opt;/* Encoder option */
-       u8 op_align;    /* op align 0- 16 bit, 1- MSB, 2 LSB */
-       u8 reserved;    /* reserved */
-} __packed;
-
-/* Codec params struture */
-union  snd_sst_codec_params {
-       struct snd_pcm_params pcm_params;
-       struct snd_mp3_params mp3_params;
-       struct snd_aac_params aac_params;
-       struct snd_wma_params wma_params;
-} __packed;
-
-/* Address and size info of a frame buffer */
-struct sst_address_info {
-       u32 addr; /* Address at IA */
-       u32 size; /* Size of the buffer */
-};
-
-struct snd_sst_alloc_params_ext {
-       __u16 sg_count;
-       __u16 reserved;
-       __u32 frag_size;        /*Number of samples after which period elapsed
-                                 message is sent valid only if path  = 0*/
-       struct sst_address_info  ring_buf_info[8];
-};
-
-struct snd_sst_stream_params {
-       union snd_sst_codec_params uc;
-} __packed;
-
-struct snd_sst_params {
-       u32 result;
-       u32 stream_id;
-       u8 codec;
-       u8 ops;
-       u8 stream_type;
-       u8 device_type;
-       u8 task;
-       struct snd_sst_stream_params sparams;
-       struct snd_sst_alloc_params_ext aparams;
-};
-
-struct snd_sst_alloc_mrfld {
-       u16 codec_type;
-       u8 operation;
-       u8 sg_count;
-       struct sst_address_info ring_buf_info[8];
-       u32 frag_size;
-       u32 ts;
-       struct snd_sst_stream_params codec_params;
-} __packed;
-
-/* Alloc stream params structure */
-struct snd_sst_alloc_params {
-       struct snd_sst_str_type str_type;
-       struct snd_sst_stream_params stream_params;
-       struct snd_sst_alloc_params_ext alloc_params;
-} __packed;
-
-/* Alloc stream response message */
-struct snd_sst_alloc_response {
-       struct snd_sst_str_type str_type; /* Stream type for allocation */
-       struct snd_sst_lib_download lib_dnld; /* Valid only for codec dnld */
-};
-
-/* Drop response */
-struct snd_sst_drop_response {
-       u32 result;
-       u32 bytes;
-};
-
-struct snd_sst_async_msg {
-       u32 msg_id; /* Async msg id */
-       u32 payload[0];
-};
-
-struct snd_sst_async_err_msg {
-       u32 fw_resp; /* Firmware Result */
-       u32 lib_resp; /*Library result */
-} __packed;
-
-struct snd_sst_vol {
-       u32     stream_id;
-       s32     volume;
-       u32     ramp_duration;
-       u32     ramp_type;              /* Ramp type, default=0 */
-};
-
-/* Gain library parameters for mrfld
- * based on DSP command spec v0.82
- */
-struct snd_sst_gain_v2 {
-       u16 gain_cell_num;  /* num of gain cells to modify*/
-       u8 cell_nbr_idx; /* instance index*/
-       u8 cell_path_idx; /* pipe-id */
-       u16 module_id; /*module id */
-       u16 left_cell_gain; /* left gain value in dB*/
-       u16 right_cell_gain; /* right gain value in dB*/
-       u16 gain_time_const; /* gain time constant*/
-} __packed;
-
-struct snd_sst_mute {
-       u32     stream_id;
-       u32     mute;
-};
-
-struct snd_sst_runtime_params {
-       u8 type;
-       u8 str_id;
-       u8 size;
-       u8 rsvd;
-       void *addr;
-} __packed;
-
-enum stream_param_type {
-       SST_SET_TIME_SLOT = 0,
-       SST_SET_CHANNEL_INFO = 1,
-       OTHERS = 2, /*reserved for future params*/
-};
-
-/* CSV Voice call routing structure */
-struct snd_sst_control_routing {
-       u8 control; /* 0=start, 1=Stop */
-       u8 reserved[3]; /* Reserved- for 32 bit alignment */
-};
-
-struct ipc_post {
-       struct list_head node;
-       union ipc_header header; /* driver specific */
-       bool is_large;
-       bool is_process_reply;
-       union ipc_header_mrfld mrfld_header;
-       char *mailbox_data;
-};
-
-struct snd_sst_ctxt_params {
-       u32 address; /* Physical Address in DDR where the context is stored */
-       u32 size; /* size of the context */
-};
-
-struct snd_sst_lpe_log_params {
-       u8 dbg_type;
-       u8 module_id;
-       u8 log_level;
-       u8 reserved;
-} __packed;
-
-enum snd_sst_bytes_type {
-       SND_SST_BYTES_SET = 0x1,
-       SND_SST_BYTES_GET = 0x2,
-};
-
-struct snd_sst_bytes_v2 {
-       u8 type;
-       u8 ipc_msg;
-       u8 block;
-       u8 task_id;
-       u8 pipe_id;
-       u8 rsvd;
-       u16 len;
-       char bytes[0];
-};
-
-#define MAX_VTSV_FILES 2
-struct snd_sst_vtsv_info {
-       struct sst_address_info vfiles[MAX_VTSV_FILES];
-} __packed;
-
-#endif /* __SST_MFLD_DSP_H__ */
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c
deleted file mode 100644 (file)
index 3951689..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- *  sst_mfld_platform.c - Intel MID Platform driver
- *
- *  Copyright (C) 2010-2014 Intel Corp
- *  Author: Vinod Koul <vinod.koul@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include "sst-mfld-platform.h"
-
-/* compress stream operations */
-static void sst_compr_fragment_elapsed(void *arg)
-{
-       struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
-
-       pr_debug("fragment elapsed by driver\n");
-       if (cstream)
-               snd_compr_fragment_elapsed(cstream);
-}
-
-static void sst_drain_notify(void *arg)
-{
-       struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
-
-       pr_debug("drain notify by driver\n");
-       if (cstream)
-               snd_compr_drain_notify(cstream);
-}
-
-static int sst_platform_compr_open(struct snd_compr_stream *cstream)
-{
-
-       int ret_val = 0;
-       struct snd_compr_runtime *runtime = cstream->runtime;
-       struct sst_runtime_stream *stream;
-
-       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-       if (!stream)
-               return -ENOMEM;
-
-       spin_lock_init(&stream->status_lock);
-
-       /* get the sst ops */
-       if (!sst || !try_module_get(sst->dev->driver->owner)) {
-               pr_err("no device available to run\n");
-               ret_val = -ENODEV;
-               goto out_ops;
-       }
-       stream->compr_ops = sst->compr_ops;
-       stream->id = 0;
-
-       /* Turn on LPE */
-       sst->compr_ops->power(sst->dev, true);
-
-       sst_set_stream_status(stream, SST_PLATFORM_INIT);
-       runtime->private_data = stream;
-       return 0;
-out_ops:
-       kfree(stream);
-       return ret_val;
-}
-
-static int sst_platform_compr_free(struct snd_compr_stream *cstream)
-{
-       struct sst_runtime_stream *stream;
-       int ret_val = 0, str_id;
-
-       stream = cstream->runtime->private_data;
-       /* Turn off LPE */
-       sst->compr_ops->power(sst->dev, false);
-
-       /*need to check*/
-       str_id = stream->id;
-       if (str_id)
-               ret_val = stream->compr_ops->close(sst->dev, str_id);
-       module_put(sst->dev->driver->owner);
-       kfree(stream);
-       pr_debug("%s: %d\n", __func__, ret_val);
-       return 0;
-}
-
-static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
-                                       struct snd_compr_params *params)
-{
-       struct sst_runtime_stream *stream;
-       int retval;
-       struct snd_sst_params str_params;
-       struct sst_compress_cb cb;
-       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
-
-       stream = cstream->runtime->private_data;
-       /* construct fw structure for this*/
-       memset(&str_params, 0, sizeof(str_params));
-
-       /* fill the device type and stream id to pass to SST driver */
-       retval = sst_fill_stream_params(cstream, ctx, &str_params, true);
-       pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval);
-       if (retval < 0)
-               return retval;
-
-       switch (params->codec.id) {
-       case SND_AUDIOCODEC_MP3: {
-               str_params.codec = SST_CODEC_TYPE_MP3;
-               str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
-               str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
-               break;
-       }
-
-       case SND_AUDIOCODEC_AAC: {
-               str_params.codec = SST_CODEC_TYPE_AAC;
-               str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
-               str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
-               if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
-                       str_params.sparams.uc.aac_params.bs_format =
-                                                       AAC_BIT_STREAM_ADTS;
-               else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
-                       str_params.sparams.uc.aac_params.bs_format =
-                                                       AAC_BIT_STREAM_RAW;
-               else {
-                       pr_err("Undefined format%d\n", params->codec.format);
-                       return -EINVAL;
-               }
-               str_params.sparams.uc.aac_params.externalsr =
-                                               params->codec.sample_rate;
-               break;
-       }
-
-       default:
-               pr_err("codec not supported, id =%d\n", params->codec.id);
-               return -EINVAL;
-       }
-
-       str_params.aparams.ring_buf_info[0].addr  =
-                                       virt_to_phys(cstream->runtime->buffer);
-       str_params.aparams.ring_buf_info[0].size =
-                                       cstream->runtime->buffer_size;
-       str_params.aparams.sg_count = 1;
-       str_params.aparams.frag_size = cstream->runtime->fragment_size;
-
-       cb.param = cstream;
-       cb.compr_cb = sst_compr_fragment_elapsed;
-       cb.drain_cb_param = cstream;
-       cb.drain_notify = sst_drain_notify;
-
-       retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
-       if (retval < 0) {
-               pr_err("stream allocation failed %d\n", retval);
-               return retval;
-       }
-
-       stream->id = retval;
-       return 0;
-}
-
-static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
-{
-       struct sst_runtime_stream *stream = cstream->runtime->private_data;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               if (stream->compr_ops->stream_start)
-                       return stream->compr_ops->stream_start(sst->dev, stream->id);
-       case SNDRV_PCM_TRIGGER_STOP:
-               if (stream->compr_ops->stream_drop)
-                       return stream->compr_ops->stream_drop(sst->dev, stream->id);
-       case SND_COMPR_TRIGGER_DRAIN:
-               if (stream->compr_ops->stream_drain)
-                       return stream->compr_ops->stream_drain(sst->dev, stream->id);
-       case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
-               if (stream->compr_ops->stream_partial_drain)
-                       return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (stream->compr_ops->stream_pause)
-                       return stream->compr_ops->stream_pause(sst->dev, stream->id);
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (stream->compr_ops->stream_pause_release)
-                       return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
-       default:
-               return -EINVAL;
-       }
-}
-
-static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
-                                       struct snd_compr_tstamp *tstamp)
-{
-       struct sst_runtime_stream *stream;
-
-       stream  = cstream->runtime->private_data;
-       stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
-       tstamp->byte_offset = tstamp->copied_total %
-                                (u32)cstream->runtime->buffer_size;
-       pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
-       return 0;
-}
-
-static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
-                                       size_t bytes)
-{
-       struct sst_runtime_stream *stream;
-
-       stream  = cstream->runtime->private_data;
-       stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
-       stream->bytes_written += bytes;
-
-       return 0;
-}
-
-static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
-                                       struct snd_compr_caps *caps)
-{
-       struct sst_runtime_stream *stream =
-               cstream->runtime->private_data;
-
-       return stream->compr_ops->get_caps(caps);
-}
-
-static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
-                                       struct snd_compr_codec_caps *codec)
-{
-       struct sst_runtime_stream *stream =
-               cstream->runtime->private_data;
-
-       return stream->compr_ops->get_codec_caps(codec);
-}
-
-static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
-                                       struct snd_compr_metadata *metadata)
-{
-       struct sst_runtime_stream *stream  =
-                cstream->runtime->private_data;
-
-       return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
-}
-
-struct snd_compr_ops sst_platform_compr_ops = {
-
-       .open = sst_platform_compr_open,
-       .free = sst_platform_compr_free,
-       .set_params = sst_platform_compr_set_params,
-       .set_metadata = sst_platform_compr_set_metadata,
-       .trigger = sst_platform_compr_trigger,
-       .pointer = sst_platform_compr_pointer,
-       .ack = sst_platform_compr_ack,
-       .get_caps = sst_platform_compr_get_caps,
-       .get_codec_caps = sst_platform_compr_get_codec_caps,
-};
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c
deleted file mode 100644 (file)
index 7523cbe..0000000
+++ /dev/null
@@ -1,744 +0,0 @@
-/*
- *  sst_mfld_platform.c - Intel MID Platform driver
- *
- *  Copyright (C) 2010-2014 Intel Corp
- *  Author: Vinod Koul <vinod.koul@intel.com>
- *  Author: Harsha Priya <priya.harsha@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include <asm/platform_sst_audio.h>
-#include "sst-mfld-platform.h"
-#include "sst-atom-controls.h"
-
-struct sst_device *sst;
-static DEFINE_MUTEX(sst_lock);
-extern struct snd_compr_ops sst_platform_compr_ops;
-
-int sst_register_dsp(struct sst_device *dev)
-{
-       if (WARN_ON(!dev))
-               return -EINVAL;
-       if (!try_module_get(dev->dev->driver->owner))
-               return -ENODEV;
-       mutex_lock(&sst_lock);
-       if (sst) {
-               dev_err(dev->dev, "we already have a device %s\n", sst->name);
-               module_put(dev->dev->driver->owner);
-               mutex_unlock(&sst_lock);
-               return -EEXIST;
-       }
-       dev_dbg(dev->dev, "registering device %s\n", dev->name);
-       sst = dev;
-       mutex_unlock(&sst_lock);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_register_dsp);
-
-int sst_unregister_dsp(struct sst_device *dev)
-{
-       if (WARN_ON(!dev))
-               return -EINVAL;
-       if (dev != sst)
-               return -EINVAL;
-
-       mutex_lock(&sst_lock);
-
-       if (!sst) {
-               mutex_unlock(&sst_lock);
-               return -EIO;
-       }
-
-       module_put(sst->dev->driver->owner);
-       dev_dbg(dev->dev, "unreg %s\n", sst->name);
-       sst = NULL;
-       mutex_unlock(&sst_lock);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_unregister_dsp);
-
-static struct snd_pcm_hardware sst_platform_pcm_hw = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED |
-                       SNDRV_PCM_INFO_DOUBLE |
-                       SNDRV_PCM_INFO_PAUSE |
-                       SNDRV_PCM_INFO_RESUME |
-                       SNDRV_PCM_INFO_MMAP|
-                       SNDRV_PCM_INFO_MMAP_VALID |
-                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                       SNDRV_PCM_INFO_SYNC_START),
-       .buffer_bytes_max = SST_MAX_BUFFER,
-       .period_bytes_min = SST_MIN_PERIOD_BYTES,
-       .period_bytes_max = SST_MAX_PERIOD_BYTES,
-       .periods_min = SST_MIN_PERIODS,
-       .periods_max = SST_MAX_PERIODS,
-       .fifo_size = SST_FIFO_SIZE,
-};
-
-static struct sst_dev_stream_map dpcm_strm_map[] = {
-       {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */
-       {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0},
-       {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0},
-       {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
-};
-
-static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
-{
-
-       return sst_send_pipe_gains(dai, stream, mute);
-}
-
-/* helper functions */
-void sst_set_stream_status(struct sst_runtime_stream *stream,
-                                       int state)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&stream->status_lock, flags);
-       stream->stream_status = state;
-       spin_unlock_irqrestore(&stream->status_lock, flags);
-}
-
-static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
-{
-       int state;
-       unsigned long flags;
-
-       spin_lock_irqsave(&stream->status_lock, flags);
-       state = stream->stream_status;
-       spin_unlock_irqrestore(&stream->status_lock, flags);
-       return state;
-}
-
-static void sst_fill_alloc_params(struct snd_pcm_substream *substream,
-                               struct snd_sst_alloc_params_ext *alloc_param)
-{
-       unsigned int channels;
-       snd_pcm_uframes_t period_size;
-       ssize_t periodbytes;
-       ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
-       u32 buffer_addr = virt_to_phys(substream->dma_buffer.area);
-
-       channels = substream->runtime->channels;
-       period_size = substream->runtime->period_size;
-       periodbytes = samples_to_bytes(substream->runtime, period_size);
-       alloc_param->ring_buf_info[0].addr = buffer_addr;
-       alloc_param->ring_buf_info[0].size = buffer_bytes;
-       alloc_param->sg_count = 1;
-       alloc_param->reserved = 0;
-       alloc_param->frag_size = periodbytes * channels;
-
-}
-static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
-                               struct snd_sst_stream_params *param)
-{
-       param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
-       param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
-       param->uc.pcm_params.sfreq = substream->runtime->rate;
-
-       /* PCM stream via ALSA interface */
-       param->uc.pcm_params.use_offload_path = 0;
-       param->uc.pcm_params.reserved2 = 0;
-       memset(param->uc.pcm_params.channel_map, 0, sizeof(u8));
-
-}
-
-static int sst_get_stream_mapping(int dev, int sdev, int dir,
-       struct sst_dev_stream_map *map, int size)
-{
-       int i;
-
-       if (map == NULL)
-               return -EINVAL;
-
-
-       /* index 0 is not used in stream map */
-       for (i = 1; i < size; i++) {
-               if ((map[i].dev_num == dev) && (map[i].direction == dir))
-                       return i;
-       }
-       return 0;
-}
-
-int sst_fill_stream_params(void *substream,
-       const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress)
-{
-       int map_size;
-       int index;
-       struct sst_dev_stream_map *map;
-       struct snd_pcm_substream *pstream = NULL;
-       struct snd_compr_stream *cstream = NULL;
-
-       map = ctx->pdata->pdev_strm_map;
-       map_size = ctx->pdata->strm_map_size;
-
-       if (is_compress == true)
-               cstream = (struct snd_compr_stream *)substream;
-       else
-               pstream = (struct snd_pcm_substream *)substream;
-
-       str_params->stream_type = SST_STREAM_TYPE_MUSIC;
-
-       /* For pcm streams */
-       if (pstream) {
-               index = sst_get_stream_mapping(pstream->pcm->device,
-                                         pstream->number, pstream->stream,
-                                         map, map_size);
-               if (index <= 0)
-                       return -EINVAL;
-
-               str_params->stream_id = index;
-               str_params->device_type = map[index].device_id;
-               str_params->task = map[index].task_id;
-
-               str_params->ops = (u8)pstream->stream;
-       }
-
-       if (cstream) {
-               index = sst_get_stream_mapping(cstream->device->device,
-                                              0, cstream->direction,
-                                              map, map_size);
-               if (index <= 0)
-                       return -EINVAL;
-               str_params->stream_id = index;
-               str_params->device_type = map[index].device_id;
-               str_params->task = map[index].task_id;
-
-               str_params->ops = (u8)cstream->direction;
-       }
-       return 0;
-}
-
-static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       struct sst_runtime_stream *stream =
-                       substream->runtime->private_data;
-       struct snd_sst_stream_params param = {{{0,},},};
-       struct snd_sst_params str_params = {0};
-       struct snd_sst_alloc_params_ext alloc_params = {0};
-       int ret_val = 0;
-       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
-
-       /* set codec params and inform SST driver the same */
-       sst_fill_pcm_params(substream, &param);
-       sst_fill_alloc_params(substream, &alloc_params);
-       substream->runtime->dma_area = substream->dma_buffer.area;
-       str_params.sparams = param;
-       str_params.aparams = alloc_params;
-       str_params.codec = SST_CODEC_TYPE_PCM;
-
-       /* fill the device type and stream id to pass to SST driver */
-       ret_val = sst_fill_stream_params(substream, ctx, &str_params, false);
-       if (ret_val < 0)
-               return ret_val;
-
-       stream->stream_info.str_id = str_params.stream_id;
-
-       ret_val = stream->ops->open(sst->dev, &str_params);
-       if (ret_val <= 0)
-               return ret_val;
-
-
-       return ret_val;
-}
-
-static void sst_period_elapsed(void *arg)
-{
-       struct snd_pcm_substream *substream = arg;
-       struct sst_runtime_stream *stream;
-       int status;
-
-       if (!substream || !substream->runtime)
-               return;
-       stream = substream->runtime->private_data;
-       if (!stream)
-               return;
-       status = sst_get_stream_status(stream);
-       if (status != SST_PLATFORM_RUNNING)
-               return;
-       snd_pcm_period_elapsed(substream);
-}
-
-static int sst_platform_init_stream(struct snd_pcm_substream *substream)
-{
-       struct sst_runtime_stream *stream =
-                       substream->runtime->private_data;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int ret_val;
-
-       dev_dbg(rtd->dev, "setting buffer ptr param\n");
-       sst_set_stream_status(stream, SST_PLATFORM_INIT);
-       stream->stream_info.period_elapsed = sst_period_elapsed;
-       stream->stream_info.arg = substream;
-       stream->stream_info.buffer_ptr = 0;
-       stream->stream_info.sfreq = substream->runtime->rate;
-       ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
-       if (ret_val)
-               dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
-       return ret_val;
-
-}
-
-static int power_up_sst(struct sst_runtime_stream *stream)
-{
-       return stream->ops->power(sst->dev, true);
-}
-
-static void power_down_sst(struct sst_runtime_stream *stream)
-{
-       stream->ops->power(sst->dev, false);
-}
-
-static int sst_media_open(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       int ret_val = 0;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sst_runtime_stream *stream;
-
-       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-       if (!stream)
-               return -ENOMEM;
-       spin_lock_init(&stream->status_lock);
-
-       /* get the sst ops */
-       mutex_lock(&sst_lock);
-       if (!sst ||
-           !try_module_get(sst->dev->driver->owner)) {
-               dev_err(dai->dev, "no device available to run\n");
-               ret_val = -ENODEV;
-               goto out_ops;
-       }
-       stream->ops = sst->ops;
-       mutex_unlock(&sst_lock);
-
-       stream->stream_info.str_id = 0;
-
-       stream->stream_info.arg = substream;
-       /* allocate memory for SST API set */
-       runtime->private_data = stream;
-
-       ret_val = power_up_sst(stream);
-       if (ret_val < 0)
-               return ret_val;
-
-       /* Make sure, that the period size is always even */
-       snd_pcm_hw_constraint_step(substream->runtime, 0,
-                          SNDRV_PCM_HW_PARAM_PERIODS, 2);
-
-       return snd_pcm_hw_constraint_integer(runtime,
-                        SNDRV_PCM_HW_PARAM_PERIODS);
-out_ops:
-       kfree(stream);
-       mutex_unlock(&sst_lock);
-       return ret_val;
-}
-
-static void sst_media_close(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       struct sst_runtime_stream *stream;
-       int ret_val = 0, str_id;
-
-       stream = substream->runtime->private_data;
-       power_down_sst(stream);
-
-       str_id = stream->stream_info.str_id;
-       if (str_id)
-               ret_val = stream->ops->close(sst->dev, str_id);
-       module_put(sst->dev->driver->owner);
-       kfree(stream);
-}
-
-static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
-                                              struct snd_pcm_substream *substream)
-{
-       struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
-       struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
-       struct sst_runtime_stream *stream =
-                       substream->runtime->private_data;
-       u32 str_id = stream->stream_info.str_id;
-       unsigned int pipe_id;
-
-       pipe_id = map[str_id].device_id;
-
-       dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
-                       pipe_id, str_id);
-       return pipe_id;
-}
-
-static int sst_media_prepare(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       struct sst_runtime_stream *stream;
-       int ret_val = 0, str_id;
-
-       stream = substream->runtime->private_data;
-       str_id = stream->stream_info.str_id;
-       if (stream->stream_info.str_id) {
-               ret_val = stream->ops->stream_drop(sst->dev, str_id);
-               return ret_val;
-       }
-
-       ret_val = sst_platform_alloc_stream(substream, dai);
-       if (ret_val <= 0)
-               return ret_val;
-       snprintf(substream->pcm->id, sizeof(substream->pcm->id),
-                       "%d", stream->stream_info.str_id);
-
-       ret_val = sst_platform_init_stream(substream);
-       if (ret_val)
-               return ret_val;
-       substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
-       return ret_val;
-}
-
-static int sst_media_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params,
-                               struct snd_soc_dai *dai)
-{
-       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-       memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
-       return 0;
-}
-
-static int sst_media_hw_free(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static int sst_enable_ssp(struct snd_pcm_substream *substream,
-                       struct snd_soc_dai *dai)
-{
-       int ret = 0;
-
-       if (!dai->active) {
-               ret = sst_handle_vb_timer(dai, true);
-               if (ret)
-                       return ret;
-               ret = send_ssp_cmd(dai, dai->name, 1);
-       }
-       return ret;
-}
-
-static void sst_disable_ssp(struct snd_pcm_substream *substream,
-                       struct snd_soc_dai *dai)
-{
-       if (!dai->active) {
-               send_ssp_cmd(dai, dai->name, 0);
-               sst_handle_vb_timer(dai, false);
-       }
-}
-
-static struct snd_soc_dai_ops sst_media_dai_ops = {
-       .startup = sst_media_open,
-       .shutdown = sst_media_close,
-       .prepare = sst_media_prepare,
-       .hw_params = sst_media_hw_params,
-       .hw_free = sst_media_hw_free,
-       .mute_stream = sst_media_digital_mute,
-};
-
-static struct snd_soc_dai_ops sst_compr_dai_ops = {
-       .mute_stream = sst_media_digital_mute,
-};
-
-static struct snd_soc_dai_ops sst_be_dai_ops = {
-       .startup = sst_enable_ssp,
-       .shutdown = sst_disable_ssp,
-};
-
-static struct snd_soc_dai_driver sst_platform_dai[] = {
-{
-       .name = "media-cpu-dai",
-       .ops = &sst_media_dai_ops,
-       .playback = {
-               .stream_name = "Headset Playback",
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .stream_name = "Headset Capture",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-{
-       .name = "compress-cpu-dai",
-       .compress_dai = 1,
-       .ops = &sst_compr_dai_ops,
-       .playback = {
-               .stream_name = "Compress Playback",
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-/* BE CPU  Dais */
-{
-       .name = "ssp0-port",
-       .ops = &sst_be_dai_ops,
-       .playback = {
-               .stream_name = "ssp0 Tx",
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .stream_name = "ssp0 Rx",
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-{
-       .name = "ssp1-port",
-       .ops = &sst_be_dai_ops,
-       .playback = {
-               .stream_name = "ssp1 Tx",
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .stream_name = "ssp1 Rx",
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-{
-       .name = "ssp2-port",
-       .ops = &sst_be_dai_ops,
-       .playback = {
-               .stream_name = "ssp2 Tx",
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .stream_name = "ssp2 Rx",
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-};
-
-static int sst_platform_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime;
-
-       if (substream->pcm->internal)
-               return 0;
-
-       runtime = substream->runtime;
-       runtime->hw = sst_platform_pcm_hw;
-       return 0;
-}
-
-static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
-                                       int cmd)
-{
-       int ret_val = 0, str_id;
-       struct sst_runtime_stream *stream;
-       int status;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
-       if (substream->pcm->internal)
-               return 0;
-       stream = substream->runtime->private_data;
-       str_id = stream->stream_info.str_id;
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               dev_dbg(rtd->dev, "sst: Trigger Start\n");
-               status = SST_PLATFORM_RUNNING;
-               stream->stream_info.arg = substream;
-               ret_val = stream->ops->stream_start(sst->dev, str_id);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               dev_dbg(rtd->dev, "sst: in stop\n");
-               status = SST_PLATFORM_DROPPED;
-               ret_val = stream->ops->stream_drop(sst->dev, str_id);
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               dev_dbg(rtd->dev, "sst: in pause\n");
-               status = SST_PLATFORM_PAUSED;
-               ret_val = stream->ops->stream_pause(sst->dev, str_id);
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               dev_dbg(rtd->dev, "sst: in pause release\n");
-               status = SST_PLATFORM_RUNNING;
-               ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (!ret_val)
-               sst_set_stream_status(stream, status);
-
-       return ret_val;
-}
-
-
-static snd_pcm_uframes_t sst_platform_pcm_pointer
-                       (struct snd_pcm_substream *substream)
-{
-       struct sst_runtime_stream *stream;
-       int ret_val, status;
-       struct pcm_stream_info *str_info;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       stream = substream->runtime->private_data;
-       status = sst_get_stream_status(stream);
-       if (status == SST_PLATFORM_INIT)
-               return 0;
-       str_info = &stream->stream_info;
-       ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
-       if (ret_val) {
-               dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
-               return ret_val;
-       }
-       substream->runtime->delay = str_info->pcm_delay;
-       return str_info->buffer_ptr;
-}
-
-static struct snd_pcm_ops sst_platform_ops = {
-       .open = sst_platform_open,
-       .ioctl = snd_pcm_lib_ioctl,
-       .trigger = sst_platform_pcm_trigger,
-       .pointer = sst_platform_pcm_pointer,
-};
-
-static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_dai *dai = rtd->cpu_dai;
-       struct snd_pcm *pcm = rtd->pcm;
-       int retval = 0;
-
-       if (dai->driver->playback.channels_min ||
-                       dai->driver->capture.channels_min) {
-               retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
-                       SNDRV_DMA_TYPE_CONTINUOUS,
-                       snd_dma_continuous_data(GFP_DMA),
-                       SST_MIN_BUFFER, SST_MAX_BUFFER);
-               if (retval) {
-                       dev_err(rtd->dev, "dma buffer allocationf fail\n");
-                       return retval;
-               }
-       }
-       return retval;
-}
-
-static int sst_soc_probe(struct snd_soc_platform *platform)
-{
-       return sst_dsp_init_v2_dpcm(platform);
-}
-
-static struct snd_soc_platform_driver sst_soc_platform_drv  = {
-       .probe          = sst_soc_probe,
-       .ops            = &sst_platform_ops,
-       .compr_ops      = &sst_platform_compr_ops,
-       .pcm_new        = sst_pcm_new,
-};
-
-static const struct snd_soc_component_driver sst_component = {
-       .name           = "sst",
-};
-
-
-static int sst_platform_probe(struct platform_device *pdev)
-{
-       struct sst_data *drv;
-       int ret;
-       struct sst_platform_data *pdata;
-
-       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
-       if (drv == NULL) {
-               return -ENOMEM;
-       }
-
-       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-       if (pdata == NULL) {
-               return -ENOMEM;
-       }
-
-       pdata->pdev_strm_map = dpcm_strm_map;
-       pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map);
-       drv->pdata = pdata;
-       drv->pdev = pdev;
-       mutex_init(&drv->lock);
-       dev_set_drvdata(&pdev->dev, drv);
-
-       ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
-       if (ret) {
-               dev_err(&pdev->dev, "registering soc platform failed\n");
-               return ret;
-       }
-
-       ret = snd_soc_register_component(&pdev->dev, &sst_component,
-                               sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
-       if (ret) {
-               dev_err(&pdev->dev, "registering cpu dais failed\n");
-               snd_soc_unregister_platform(&pdev->dev);
-       }
-       return ret;
-}
-
-static int sst_platform_remove(struct platform_device *pdev)
-{
-
-       snd_soc_unregister_component(&pdev->dev);
-       snd_soc_unregister_platform(&pdev->dev);
-       dev_dbg(&pdev->dev, "sst_platform_remove success\n");
-       return 0;
-}
-
-static struct platform_driver sst_platform_driver = {
-       .driver         = {
-               .name           = "sst-mfld-platform",
-       },
-       .probe          = sst_platform_probe,
-       .remove         = sst_platform_remove,
-};
-
-module_platform_driver(sst_platform_driver);
-
-MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
-MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
-MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sst-mfld-platform");
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h
deleted file mode 100644 (file)
index 79c8d12..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- *  sst_mfld_platform.h - Intel MID Platform driver header file
- *
- *  Copyright (C) 2010 Intel Corp
- *  Author: Vinod Koul <vinod.koul@intel.com>
- *  Author: Harsha Priya <priya.harsha@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#ifndef __SST_PLATFORMDRV_H__
-#define __SST_PLATFORMDRV_H__
-
-#include "sst-mfld-dsp.h"
-
-extern struct sst_device *sst;
-
-#define SST_MONO               1
-#define SST_STEREO             2
-#define SST_MAX_CAP            5
-
-#define SST_MAX_BUFFER         (800*1024)
-#define SST_MIN_BUFFER         (800*1024)
-#define SST_MIN_PERIOD_BYTES   32
-#define SST_MAX_PERIOD_BYTES   SST_MAX_BUFFER
-#define SST_MIN_PERIODS                2
-#define SST_MAX_PERIODS                (1024*2)
-#define SST_FIFO_SIZE          0
-
-struct pcm_stream_info {
-       int str_id;
-       void *arg;
-       void (*period_elapsed) (void *arg);
-       unsigned long long buffer_ptr;
-       unsigned long long pcm_delay;
-       int sfreq;
-};
-
-enum sst_drv_status {
-       SST_PLATFORM_INIT = 1,
-       SST_PLATFORM_STARTED,
-       SST_PLATFORM_RUNNING,
-       SST_PLATFORM_PAUSED,
-       SST_PLATFORM_DROPPED,
-};
-
-enum sst_stream_ops {
-       STREAM_OPS_PLAYBACK = 0,
-       STREAM_OPS_CAPTURE,
-};
-
-enum sst_audio_device_type {
-       SND_SST_DEVICE_HEADSET = 1,
-       SND_SST_DEVICE_IHF,
-       SND_SST_DEVICE_VIBRA,
-       SND_SST_DEVICE_HAPTIC,
-       SND_SST_DEVICE_CAPTURE,
-       SND_SST_DEVICE_COMPRESS,
-};
-
-/* PCM Parameters */
-struct sst_pcm_params {
-       u16 codec;      /* codec type */
-       u8 num_chan;    /* 1=Mono, 2=Stereo */
-       u8 pcm_wd_sz;   /* 16/24 - bit*/
-       u32 reserved;   /* Bitrate in bits per second */
-       u32 sfreq;      /* Sampling rate in Hz */
-       u32 ring_buffer_size;
-       u32 period_count;       /* period elapsed in samples*/
-       u32 ring_buffer_addr;
-};
-
-struct sst_stream_params {
-       u32 result;
-       u32 stream_id;
-       u8 codec;
-       u8 ops;
-       u8 stream_type;
-       u8 device_type;
-       struct sst_pcm_params sparams;
-};
-
-struct sst_compress_cb {
-       void *param;
-       void (*compr_cb)(void *param);
-       void *drain_cb_param;
-       void (*drain_notify)(void *param);
-};
-
-struct compress_sst_ops {
-       const char *name;
-       int (*open)(struct device *dev,
-               struct snd_sst_params *str_params, struct sst_compress_cb *cb);
-       int (*stream_start)(struct device *dev, unsigned int str_id);
-       int (*stream_drop)(struct device *dev, unsigned int str_id);
-       int (*stream_drain)(struct device *dev, unsigned int str_id);
-       int (*stream_partial_drain)(struct device *dev, unsigned int str_id);
-       int (*stream_pause)(struct device *dev, unsigned int str_id);
-       int (*stream_pause_release)(struct device *dev, unsigned int str_id);
-
-       int (*tstamp)(struct device *dev, unsigned int str_id,
-                       struct snd_compr_tstamp *tstamp);
-       int (*ack)(struct device *dev, unsigned int str_id,
-                       unsigned long bytes);
-       int (*close)(struct device *dev, unsigned int str_id);
-       int (*get_caps)(struct snd_compr_caps *caps);
-       int (*get_codec_caps)(struct snd_compr_codec_caps *codec);
-       int (*set_metadata)(struct device *dev, unsigned int str_id,
-                       struct snd_compr_metadata *mdata);
-       int (*power)(struct device *dev, bool state);
-};
-
-struct sst_ops {
-       int (*open)(struct device *dev, struct snd_sst_params *str_param);
-       int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info);
-       int (*stream_start)(struct device *dev, int str_id);
-       int (*stream_drop)(struct device *dev, int str_id);
-       int (*stream_pause)(struct device *dev, int str_id);
-       int (*stream_pause_release)(struct device *dev, int str_id);
-       int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info);
-       int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes);
-       int (*close)(struct device *dev, unsigned int str_id);
-       int (*power)(struct device *dev, bool state);
-};
-
-struct sst_runtime_stream {
-       int     stream_status;
-       unsigned int id;
-       size_t bytes_written;
-       struct pcm_stream_info stream_info;
-       struct sst_ops *ops;
-       struct compress_sst_ops *compr_ops;
-       spinlock_t      status_lock;
-};
-
-struct sst_device {
-       char *name;
-       struct device *dev;
-       struct sst_ops *ops;
-       struct platform_device *pdev;
-       struct compress_sst_ops *compr_ops;
-};
-
-struct sst_data;
-
-int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform);
-int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute);
-int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable);
-int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable);
-
-void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
-int sst_fill_stream_params(void *substream, const struct sst_data *ctx,
-                          struct snd_sst_params *str_params, bool is_compress);
-
-struct sst_algo_int_control_v2 {
-       struct soc_mixer_control mc;
-       u16 module_id; /* module identifieer */
-       u16 pipe_id; /* location info: pipe_id + instance_id */
-       u16 instance_id;
-       unsigned int value; /* Value received is stored here */
-};
-struct sst_data {
-       struct platform_device *pdev;
-       struct sst_platform_data *pdata;
-       struct snd_sst_bytes_v2 *byte_stream;
-       struct mutex lock;
-};
-int sst_register_dsp(struct sst_device *sst);
-int sst_unregister_dsp(struct sst_device *sst);
-#endif
diff --git a/sound/soc/intel/sst/Makefile b/sound/soc/intel/sst/Makefile
deleted file mode 100644 (file)
index fd21726..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-snd-intel-sst-core-objs := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o
-snd-intel-sst-pci-objs += sst_pci.o
-snd-intel-sst-acpi-objs += sst_acpi.o
-
-obj-$(CONFIG_SND_SST_IPC) += snd-intel-sst-core.o
-obj-$(CONFIG_SND_SST_IPC_PCI) += snd-intel-sst-pci.o
-obj-$(CONFIG_SND_SST_IPC_ACPI) += snd-intel-sst-acpi.o
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c
deleted file mode 100644 (file)
index 8a8d56a..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- *  sst.c - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-14      Intel Corp
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com>
- *             KP Jeeja <jeeja.kp@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/firmware.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm_qos.h>
-#include <linux/async.h>
-#include <linux/acpi.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <asm/platform_sst_audio.h>
-#include "../sst-mfld-platform.h"
-#include "sst.h"
-#include "../sst-dsp.h"
-
-MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
-MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
-MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver");
-MODULE_LICENSE("GPL v2");
-
-static inline bool sst_is_process_reply(u32 msg_id)
-{
-       return ((msg_id & PROCESS_MSG) ? true : false);
-}
-
-static inline bool sst_validate_mailbox_size(unsigned int size)
-{
-       return ((size <= SST_MAILBOX_SIZE) ? true : false);
-}
-
-static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context)
-{
-       union interrupt_reg_mrfld isr;
-       union ipc_header_mrfld header;
-       union sst_imr_reg_mrfld imr;
-       struct ipc_post *msg = NULL;
-       unsigned int size = 0;
-       struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
-       irqreturn_t retval = IRQ_HANDLED;
-
-       /* Interrupt arrived, check src */
-       isr.full = sst_shim_read64(drv->shim, SST_ISRX);
-
-       if (isr.part.done_interrupt) {
-               /* Clear done bit */
-               spin_lock(&drv->ipc_spin_lock);
-               header.full = sst_shim_read64(drv->shim,
-                                       drv->ipc_reg.ipcx);
-               header.p.header_high.part.done = 0;
-               sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full);
-
-               /* write 1 to clear status register */;
-               isr.part.done_interrupt = 1;
-               sst_shim_write64(drv->shim, SST_ISRX, isr.full);
-               spin_unlock(&drv->ipc_spin_lock);
-
-               /* we can send more messages to DSP so trigger work */
-               queue_work(drv->post_msg_wq, &drv->ipc_post_msg_wq);
-               retval = IRQ_HANDLED;
-       }
-
-       if (isr.part.busy_interrupt) {
-               /* message from dsp so copy that */
-               spin_lock(&drv->ipc_spin_lock);
-               imr.full = sst_shim_read64(drv->shim, SST_IMRX);
-               imr.part.busy_interrupt = 1;
-               sst_shim_write64(drv->shim, SST_IMRX, imr.full);
-               spin_unlock(&drv->ipc_spin_lock);
-               header.full =  sst_shim_read64(drv->shim, drv->ipc_reg.ipcd);
-
-               if (sst_create_ipc_msg(&msg, header.p.header_high.part.large)) {
-                       drv->ops->clear_interrupt(drv);
-                       return IRQ_HANDLED;
-               }
-
-               if (header.p.header_high.part.large) {
-                       size = header.p.header_low_payload;
-                       if (sst_validate_mailbox_size(size)) {
-                               memcpy_fromio(msg->mailbox_data,
-                                       drv->mailbox + drv->mailbox_recv_offset, size);
-                       } else {
-                               dev_err(drv->dev,
-                                       "Mailbox not copied, payload size is: %u\n", size);
-                               header.p.header_low_payload = 0;
-                       }
-               }
-
-               msg->mrfld_header = header;
-               msg->is_process_reply =
-                       sst_is_process_reply(header.p.header_high.part.msg_id);
-               spin_lock(&drv->rx_msg_lock);
-               list_add_tail(&msg->node, &drv->rx_list);
-               spin_unlock(&drv->rx_msg_lock);
-               drv->ops->clear_interrupt(drv);
-               retval = IRQ_WAKE_THREAD;
-       }
-       return retval;
-}
-
-static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context)
-{
-       struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
-       struct ipc_post *__msg, *msg = NULL;
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
-       if (list_empty(&drv->rx_list)) {
-               spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
-               return IRQ_HANDLED;
-       }
-
-       list_for_each_entry_safe(msg, __msg, &drv->rx_list, node) {
-               list_del(&msg->node);
-               spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
-               if (msg->is_process_reply)
-                       drv->ops->process_message(msg);
-               else
-                       drv->ops->process_reply(drv, msg);
-
-               if (msg->is_large)
-                       kfree(msg->mailbox_data);
-               kfree(msg);
-               spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
-       }
-       spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
-       return IRQ_HANDLED;
-}
-
-static int sst_save_dsp_context_v2(struct intel_sst_drv *sst)
-{
-       int ret = 0;
-
-       ret = sst_prepare_and_post_msg(sst, SST_TASK_ID_MEDIA, IPC_CMD,
-                       IPC_PREP_D3, PIPE_RSVD, 0, NULL, NULL,
-                       true, true, false, true);
-
-       if (ret < 0) {
-               dev_err(sst->dev, "not suspending FW!!, Err: %d\n", ret);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-
-static struct intel_sst_ops mrfld_ops = {
-       .interrupt = intel_sst_interrupt_mrfld,
-       .irq_thread = intel_sst_irq_thread_mrfld,
-       .clear_interrupt = intel_sst_clear_intr_mrfld,
-       .start = sst_start_mrfld,
-       .reset = intel_sst_reset_dsp_mrfld,
-       .post_message = sst_post_message_mrfld,
-       .process_reply = sst_process_reply_mrfld,
-       .save_dsp_context =  sst_save_dsp_context_v2,
-       .alloc_stream = sst_alloc_stream_mrfld,
-       .post_download = sst_post_download_mrfld,
-};
-
-int sst_driver_ops(struct intel_sst_drv *sst)
-{
-
-       switch (sst->dev_id) {
-       case SST_MRFLD_PCI_ID:
-       case SST_BYT_ACPI_ID:
-       case SST_CHV_ACPI_ID:
-               sst->tstamp = SST_TIME_STAMP_MRFLD;
-               sst->ops = &mrfld_ops;
-               return 0;
-
-       default:
-               dev_err(sst->dev,
-                       "SST Driver capablities missing for dev_id: %x", sst->dev_id);
-               return -EINVAL;
-       };
-}
-
-void sst_process_pending_msg(struct work_struct *work)
-{
-       struct intel_sst_drv *ctx = container_of(work,
-                       struct intel_sst_drv, ipc_post_msg_wq);
-
-       ctx->ops->post_message(ctx, NULL, false);
-}
-
-static int sst_workqueue_init(struct intel_sst_drv *ctx)
-{
-       INIT_LIST_HEAD(&ctx->memcpy_list);
-       INIT_LIST_HEAD(&ctx->rx_list);
-       INIT_LIST_HEAD(&ctx->ipc_dispatch_list);
-       INIT_LIST_HEAD(&ctx->block_list);
-       INIT_WORK(&ctx->ipc_post_msg_wq, sst_process_pending_msg);
-       init_waitqueue_head(&ctx->wait_queue);
-
-       ctx->post_msg_wq =
-               create_singlethread_workqueue("sst_post_msg_wq");
-       if (!ctx->post_msg_wq)
-               return -EBUSY;
-       return 0;
-}
-
-static void sst_init_locks(struct intel_sst_drv *ctx)
-{
-       mutex_init(&ctx->sst_lock);
-       spin_lock_init(&ctx->rx_msg_lock);
-       spin_lock_init(&ctx->ipc_spin_lock);
-       spin_lock_init(&ctx->block_lock);
-}
-
-int sst_alloc_drv_context(struct intel_sst_drv **ctx,
-               struct device *dev, unsigned int dev_id)
-{
-       *ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL);
-       if (!(*ctx))
-               return -ENOMEM;
-
-       (*ctx)->dev = dev;
-       (*ctx)->dev_id = dev_id;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_alloc_drv_context);
-
-int sst_context_init(struct intel_sst_drv *ctx)
-{
-       int ret = 0, i;
-
-       if (!ctx->pdata)
-               return -EINVAL;
-
-       if (!ctx->pdata->probe_data)
-               return -EINVAL;
-
-       memcpy(&ctx->info, ctx->pdata->probe_data, sizeof(ctx->info));
-
-       ret = sst_driver_ops(ctx);
-       if (ret != 0)
-               return -EINVAL;
-
-       sst_init_locks(ctx);
-       sst_set_fw_state_locked(ctx, SST_RESET);
-
-       /* pvt_id 0 reserved for async messages */
-       ctx->pvt_id = 1;
-       ctx->stream_cnt = 0;
-       ctx->fw_in_mem = NULL;
-       /* we use memcpy, so set to 0 */
-       ctx->use_dma = 0;
-       ctx->use_lli = 0;
-
-       if (sst_workqueue_init(ctx))
-               return -EINVAL;
-
-       ctx->mailbox_recv_offset = ctx->pdata->ipc_info->mbox_recv_off;
-       ctx->ipc_reg.ipcx = SST_IPCX + ctx->pdata->ipc_info->ipc_offset;
-       ctx->ipc_reg.ipcd = SST_IPCD + ctx->pdata->ipc_info->ipc_offset;
-
-       dev_info(ctx->dev, "Got drv data max stream %d\n",
-                               ctx->info.max_streams);
-
-       for (i = 1; i <= ctx->info.max_streams; i++) {
-               struct stream_info *stream = &ctx->streams[i];
-
-               memset(stream, 0, sizeof(*stream));
-               stream->pipe_id = PIPE_RSVD;
-               mutex_init(&stream->lock);
-       }
-
-       /* Register the ISR */
-       ret = devm_request_threaded_irq(ctx->dev, ctx->irq_num, ctx->ops->interrupt,
-                                       ctx->ops->irq_thread, 0, SST_DRV_NAME,
-                                       ctx);
-       if (ret)
-               goto do_free_mem;
-
-       dev_dbg(ctx->dev, "Registered IRQ %#x\n", ctx->irq_num);
-
-       /* default intr are unmasked so set this as masked */
-       sst_shim_write64(ctx->shim, SST_IMRX, 0xFFFF0038);
-
-       ctx->qos = devm_kzalloc(ctx->dev,
-               sizeof(struct pm_qos_request), GFP_KERNEL);
-       if (!ctx->qos) {
-               ret = -ENOMEM;
-               goto do_free_mem;
-       }
-       pm_qos_add_request(ctx->qos, PM_QOS_CPU_DMA_LATENCY,
-                               PM_QOS_DEFAULT_VALUE);
-
-       dev_dbg(ctx->dev, "Requesting FW %s now...\n", ctx->firmware_name);
-       ret = request_firmware_nowait(THIS_MODULE, true, ctx->firmware_name,
-                                     ctx->dev, GFP_KERNEL, ctx, sst_firmware_load_cb);
-       if (ret) {
-               dev_err(ctx->dev, "Firmware download failed:%d\n", ret);
-               goto do_free_mem;
-       }
-       sst_register(ctx->dev);
-       return 0;
-
-do_free_mem:
-       destroy_workqueue(ctx->post_msg_wq);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(sst_context_init);
-
-void sst_context_cleanup(struct intel_sst_drv *ctx)
-{
-       pm_runtime_get_noresume(ctx->dev);
-       pm_runtime_disable(ctx->dev);
-       sst_unregister(ctx->dev);
-       sst_set_fw_state_locked(ctx, SST_SHUTDOWN);
-       flush_scheduled_work();
-       destroy_workqueue(ctx->post_msg_wq);
-       pm_qos_remove_request(ctx->qos);
-       kfree(ctx->fw_sg_list.src);
-       kfree(ctx->fw_sg_list.dst);
-       ctx->fw_sg_list.list_len = 0;
-       kfree(ctx->fw_in_mem);
-       ctx->fw_in_mem = NULL;
-       sst_memcpy_free_resources(ctx);
-       ctx = NULL;
-}
-EXPORT_SYMBOL_GPL(sst_context_cleanup);
-
-static inline void sst_save_shim64(struct intel_sst_drv *ctx,
-                           void __iomem *shim,
-                           struct sst_shim_regs64 *shim_regs)
-{
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
-
-       shim_regs->imrx = sst_shim_read64(shim, SST_IMRX),
-
-       spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
-}
-
-static inline void sst_restore_shim64(struct intel_sst_drv *ctx,
-                                     void __iomem *shim,
-                                     struct sst_shim_regs64 *shim_regs)
-{
-       unsigned long irq_flags;
-
-       /*
-        * we only need to restore IMRX for this case, rest will be
-        * initialize by FW or driver when firmware is loaded
-        */
-       spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
-       sst_shim_write64(shim, SST_IMRX, shim_regs->imrx),
-       spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
-}
-
-void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
-{
-       pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY);
-       pm_runtime_use_autosuspend(ctx->dev);
-       /*
-        * For acpi devices, the actual physical device state is
-        * initially active. So change the state to active before
-        * enabling the pm
-        */
-       pm_runtime_enable(ctx->dev);
-
-       if (acpi_disabled)
-               pm_runtime_set_active(ctx->dev);
-       else
-               pm_runtime_put_noidle(ctx->dev);
-
-       sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
-}
-EXPORT_SYMBOL_GPL(sst_configure_runtime_pm);
-
-static int intel_sst_runtime_suspend(struct device *dev)
-{
-       int ret = 0;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       if (ctx->sst_state == SST_RESET) {
-               dev_dbg(dev, "LPE is already in RESET state, No action\n");
-               return 0;
-       }
-       /* save fw context */
-       if (ctx->ops->save_dsp_context(ctx))
-               return -EBUSY;
-
-       /* Move the SST state to Reset */
-       sst_set_fw_state_locked(ctx, SST_RESET);
-
-       synchronize_irq(ctx->irq_num);
-       flush_workqueue(ctx->post_msg_wq);
-
-       /* save the shim registers because PMC doesn't save state */
-       sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
-
-       return ret;
-}
-
-static int intel_sst_runtime_resume(struct device *dev)
-{
-       int ret = 0;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       if (ctx->sst_state == SST_RESET) {
-               ret = sst_load_fw(ctx);
-               if (ret) {
-                       dev_err(dev, "FW download fail %d\n", ret);
-                       sst_set_fw_state_locked(ctx, SST_RESET);
-               }
-       }
-       return ret;
-}
-
-const struct dev_pm_ops intel_sst_pm = {
-       .runtime_suspend = intel_sst_runtime_suspend,
-       .runtime_resume = intel_sst_runtime_resume,
-};
-EXPORT_SYMBOL_GPL(intel_sst_pm);
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h
deleted file mode 100644 (file)
index 562bc48..0000000
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- *  sst.h - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-14 Intel Corporation
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com>
- *             KP Jeeja <jeeja.kp@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  Common private declarations for SST
- */
-#ifndef __SST_H__
-#define __SST_H__
-
-#include <linux/firmware.h>
-
-/* driver names */
-#define SST_DRV_NAME "intel_sst_driver"
-#define SST_MRFLD_PCI_ID 0x119A
-#define SST_BYT_ACPI_ID        0x80860F28
-#define SST_CHV_ACPI_ID        0x808622A8
-
-#define SST_SUSPEND_DELAY 2000
-#define FW_CONTEXT_MEM (64*1024)
-#define SST_ICCM_BOUNDARY 4
-#define SST_CONFIG_SSP_SIGN 0x7ffe8001
-
-#define MRFLD_FW_VIRTUAL_BASE 0xC0000000
-#define MRFLD_FW_DDR_BASE_OFFSET 0x0
-#define MRFLD_FW_FEATURE_BASE_OFFSET 0x4
-#define MRFLD_FW_BSS_RESET_BIT 0
-
-extern const struct dev_pm_ops intel_sst_pm;
-enum sst_states {
-       SST_FW_LOADING = 1,
-       SST_FW_RUNNING,
-       SST_RESET,
-       SST_SHUTDOWN,
-};
-
-enum sst_algo_ops {
-       SST_SET_ALGO = 0,
-       SST_GET_ALGO = 1,
-};
-
-#define SST_BLOCK_TIMEOUT      1000
-
-#define FW_SIGNATURE_SIZE      4
-#define FW_NAME_SIZE           32
-
-/* stream states */
-enum sst_stream_states {
-       STREAM_UN_INIT  = 0,    /* Freed/Not used stream */
-       STREAM_RUNNING  = 1,    /* Running */
-       STREAM_PAUSED   = 2,    /* Paused stream */
-       STREAM_DECODE   = 3,    /* stream is in decoding only state */
-       STREAM_INIT     = 4,    /* stream init, waiting for data */
-       STREAM_RESET    = 5,    /* force reset on recovery */
-};
-
-enum sst_ram_type {
-       SST_IRAM        = 1,
-       SST_DRAM        = 2,
-       SST_DDR = 5,
-       SST_CUSTOM_INFO = 7,    /* consists of FW binary information */
-};
-
-/* SST shim registers to structure mapping */
-union interrupt_reg {
-       struct {
-               u64 done_interrupt:1;
-               u64 busy_interrupt:1;
-               u64 rsvd:62;
-       } part;
-       u64 full;
-};
-
-union sst_pisr_reg {
-       struct {
-               u32 pssp0:1;
-               u32 pssp1:1;
-               u32 rsvd0:3;
-               u32 dmac:1;
-               u32 rsvd1:26;
-       } part;
-       u32 full;
-};
-
-union sst_pimr_reg {
-       struct {
-               u32 ssp0:1;
-               u32 ssp1:1;
-               u32 rsvd0:3;
-               u32 dmac:1;
-               u32 rsvd1:10;
-               u32 ssp0_sc:1;
-               u32 ssp1_sc:1;
-               u32 rsvd2:3;
-               u32 dmac_sc:1;
-               u32 rsvd3:10;
-       } part;
-       u32 full;
-};
-
-union config_status_reg_mrfld {
-       struct {
-               u64 lpe_reset:1;
-               u64 lpe_reset_vector:1;
-               u64 runstall:1;
-               u64 pwaitmode:1;
-               u64 clk_sel:3;
-               u64 rsvd2:1;
-               u64 sst_clk:3;
-               u64 xt_snoop:1;
-               u64 rsvd3:4;
-               u64 clk_sel1:6;
-               u64 clk_enable:3;
-               u64 rsvd4:6;
-               u64 slim0baseclk:1;
-               u64 rsvd:32;
-       } part;
-       u64 full;
-};
-
-union interrupt_reg_mrfld {
-       struct {
-               u64 done_interrupt:1;
-               u64 busy_interrupt:1;
-               u64 rsvd:62;
-       } part;
-       u64 full;
-};
-
-union sst_imr_reg_mrfld {
-       struct {
-               u64 done_interrupt:1;
-               u64 busy_interrupt:1;
-               u64 rsvd:62;
-       } part;
-       u64 full;
-};
-
-/**
- * struct sst_block - This structure is used to block a user/fw data call to another
- * fw/user call
- *
- * @condition: condition for blocking check
- * @ret_code: ret code when block is released
- * @data: data ptr
- * @size: size of data
- * @on: block condition
- * @msg_id: msg_id = msgid in mfld/ctp, mrfld = NULL
- * @drv_id: str_id in mfld/ctp, = drv_id in mrfld
- * @node: list head node
- */
-struct sst_block {
-       bool    condition;
-       int     ret_code;
-       void    *data;
-       u32     size;
-       bool    on;
-       u32     msg_id;
-       u32     drv_id;
-       struct list_head node;
-};
-
-/**
- * struct stream_info - structure that holds the stream information
- *
- * @status : stream current state
- * @prev : stream prev state
- * @ops : stream operation pb/cp/drm...
- * @bufs: stream buffer list
- * @lock : stream mutex for protecting state
- * @pcm_substream : PCM substream
- * @period_elapsed : PCM period elapsed callback
- * @sfreq : stream sampling freq
- * @str_type : stream type
- * @cumm_bytes : cummulative bytes decoded
- * @str_type : stream type
- * @src : stream source
- */
-struct stream_info {
-       unsigned int            status;
-       unsigned int            prev;
-       unsigned int            ops;
-       struct mutex            lock;
-
-       void                    *pcm_substream;
-       void (*period_elapsed)(void *pcm_substream);
-
-       unsigned int            sfreq;
-       u32                     cumm_bytes;
-
-       void                    *compr_cb_param;
-       void (*compr_cb)(void *compr_cb_param);
-
-       void                    *drain_cb_param;
-       void (*drain_notify)(void *drain_cb_param);
-
-       unsigned int            num_ch;
-       unsigned int            pipe_id;
-       unsigned int            str_id;
-       unsigned int            task_id;
-};
-
-#define SST_FW_SIGN "$SST"
-#define SST_FW_LIB_SIGN "$LIB"
-
-/**
- * struct sst_fw_header - FW file headers
- *
- * @signature : FW signature
- * @file_size: size of fw image
- * @modules : # of modules
- * @file_format : version of header format
- * @reserved : reserved fields
- */
-struct sst_fw_header {
-       unsigned char signature[FW_SIGNATURE_SIZE];
-       u32 file_size;
-       u32 modules;
-       u32 file_format;
-       u32 reserved[4];
-};
-
-/**
- * struct fw_module_header - module header in FW
- *
- * @signature: module signature
- * @mod_size: size of module
- * @blocks: block count
- * @type: block type
- * @entry_point: module netry point
- */
-struct fw_module_header {
-       unsigned char signature[FW_SIGNATURE_SIZE];
-       u32 mod_size;
-       u32 blocks;
-       u32 type;
-       u32 entry_point;
-};
-
-/**
- * struct fw_block_info - block header for FW
- *
- * @type: block ram type I/D
- * @size: size of block
- * @ram_offset: offset in ram
- */
-struct fw_block_info {
-       enum sst_ram_type       type;
-       u32                     size;
-       u32                     ram_offset;
-       u32                     rsvd;
-};
-
-struct sst_runtime_param {
-       struct snd_sst_runtime_params param;
-};
-
-struct sst_sg_list {
-       struct scatterlist *src;
-       struct scatterlist *dst;
-       int list_len;
-       unsigned int sg_idx;
-};
-
-struct sst_memcpy_list {
-       struct list_head memcpylist;
-       void *dstn;
-       const void *src;
-       u32 size;
-       bool is_io;
-};
-
-/*Firmware Module Information*/
-enum sst_lib_dwnld_status {
-       SST_LIB_NOT_FOUND = 0,
-       SST_LIB_FOUND,
-       SST_LIB_DOWNLOADED,
-};
-
-struct sst_module_info {
-       const char *name; /*Library name*/
-       u32     id; /*Module ID*/
-       u32     entry_pt; /*Module entry point*/
-       u8      status; /*module status*/
-       u8      rsvd1;
-       u16     rsvd2;
-};
-
-/*
- * Structure for managing the Library Region(1.5MB)
- * in DDR in Merrifield
- */
-struct sst_mem_mgr {
-       phys_addr_t current_base;
-       int avail;
-       unsigned int count;
-};
-
-struct sst_ipc_reg {
-       int ipcx;
-       int ipcd;
-};
-
-struct sst_shim_regs64 {
-       u64 csr;
-       u64 pisr;
-       u64 pimr;
-       u64 isrx;
-       u64 isrd;
-       u64 imrx;
-       u64 imrd;
-       u64 ipcx;
-       u64 ipcd;
-       u64 isrsc;
-       u64 isrlpesc;
-       u64 imrsc;
-       u64 imrlpesc;
-       u64 ipcsc;
-       u64 ipclpesc;
-       u64 clkctl;
-       u64 csr2;
-};
-
-/**
- * struct intel_sst_drv - driver ops
- *
- * @sst_state : current sst device state
- * @dev_id : device identifier, pci_id for pci devices and acpi_id for acpi
- *          devices
- * @shim : SST shim pointer
- * @mailbox : SST mailbox pointer
- * @iram : SST IRAM pointer
- * @dram : SST DRAM pointer
- * @pdata : SST info passed as a part of pci platform data
- * @shim_phy_add : SST shim phy addr
- * @shim_regs64: Struct to save shim registers
- * @ipc_dispatch_list : ipc messages dispatched
- * @rx_list : to copy the process_reply/process_msg from DSP
- * @ipc_post_msg_wq : wq to post IPC messages context
- * @mad_ops : MAD driver operations registered
- * @mad_wq : MAD driver wq
- * @post_msg_wq : wq to post IPC messages
- * @streams : sst stream contexts
- * @list_lock : sst driver list lock (deprecated)
- * @ipc_spin_lock : spin lock to handle audio shim access and ipc queue
- * @block_lock : spin lock to add block to block_list and assign pvt_id
- * @rx_msg_lock : spin lock to handle the rx messages from the DSP
- * @scard_ops : sst card ops
- * @pci : sst pci device struture
- * @dev : pointer to current device struct
- * @sst_lock : sst device lock
- * @pvt_id : sst private id
- * @stream_cnt : total sst active stream count
- * @pb_streams : total active pb streams
- * @cp_streams : total active cp streams
- * @audio_start : audio status
- * @qos                : PM Qos struct
- * firmware_name : Firmware / Library name
- */
-struct intel_sst_drv {
-       int                     sst_state;
-       int                     irq_num;
-       unsigned int            dev_id;
-       void __iomem            *ddr;
-       void __iomem            *shim;
-       void __iomem            *mailbox;
-       void __iomem            *iram;
-       void __iomem            *dram;
-       unsigned int            mailbox_add;
-       unsigned int            iram_base;
-       unsigned int            dram_base;
-       unsigned int            shim_phy_add;
-       unsigned int            iram_end;
-       unsigned int            dram_end;
-       unsigned int            ddr_end;
-       unsigned int            ddr_base;
-       unsigned int            mailbox_recv_offset;
-       struct sst_shim_regs64  *shim_regs64;
-       struct list_head        block_list;
-       struct list_head        ipc_dispatch_list;
-       struct sst_platform_info *pdata;
-       struct list_head        rx_list;
-       struct work_struct      ipc_post_msg_wq;
-       wait_queue_head_t       wait_queue;
-       struct workqueue_struct *post_msg_wq;
-       unsigned int            tstamp;
-       /* str_id 0 is not used */
-       struct stream_info      streams[MAX_NUM_STREAMS+1];
-       spinlock_t              ipc_spin_lock;
-       spinlock_t              block_lock;
-       spinlock_t              rx_msg_lock;
-       struct pci_dev          *pci;
-       struct device           *dev;
-       volatile long unsigned          pvt_id;
-       struct mutex            sst_lock;
-       unsigned int            stream_cnt;
-       unsigned int            csr_value;
-       void                    *fw_in_mem;
-       struct sst_sg_list      fw_sg_list, library_list;
-       struct intel_sst_ops    *ops;
-       struct sst_info         info;
-       struct pm_qos_request   *qos;
-       unsigned int            use_dma;
-       unsigned int            use_lli;
-       atomic_t                fw_clear_context;
-       bool                    lib_dwnld_reqd;
-       struct list_head        memcpy_list;
-       struct sst_ipc_reg      ipc_reg;
-       struct sst_mem_mgr      lib_mem_mgr;
-       /*
-        * Holder for firmware name. Due to async call it needs to be
-        * persistent till worker thread gets called
-        */
-       char firmware_name[FW_NAME_SIZE];
-};
-
-/* misc definitions */
-#define FW_DWNL_ID 0x01
-
-struct intel_sst_ops {
-       irqreturn_t (*interrupt)(int, void *);
-       irqreturn_t (*irq_thread)(int, void *);
-       void (*clear_interrupt)(struct intel_sst_drv *ctx);
-       int (*start)(struct intel_sst_drv *ctx);
-       int (*reset)(struct intel_sst_drv *ctx);
-       void (*process_reply)(struct intel_sst_drv *ctx, struct ipc_post *msg);
-       int (*post_message)(struct intel_sst_drv *ctx,
-                       struct ipc_post *msg, bool sync);
-       void (*process_message)(struct ipc_post *msg);
-       void (*set_bypass)(bool set);
-       int (*save_dsp_context)(struct intel_sst_drv *sst);
-       void (*restore_dsp_context)(void);
-       int (*alloc_stream)(struct intel_sst_drv *ctx, void *params);
-       void (*post_download)(struct intel_sst_drv *sst);
-};
-
-int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int id);
-int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int id);
-int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int id);
-int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int id);
-int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id);
-int sst_send_byte_stream_mrfld(struct intel_sst_drv *ctx,
-                       struct snd_sst_bytes_v2 *sbytes);
-int sst_set_stream_param(int str_id, struct snd_sst_params *str_param);
-int sst_set_metadata(int str_id, char *params);
-int sst_get_stream(struct intel_sst_drv *sst_drv_ctx,
-               struct snd_sst_params *str_param);
-int sst_get_stream_allocated(struct intel_sst_drv *ctx,
-               struct snd_sst_params *str_param,
-               struct snd_sst_lib_download **lib_dnld);
-int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
-               int str_id, bool partial_drain);
-int sst_post_message_mrfld(struct intel_sst_drv *ctx,
-               struct ipc_post *msg, bool sync);
-void sst_process_reply_mrfld(struct intel_sst_drv *ctx, struct ipc_post *msg);
-int sst_start_mrfld(struct intel_sst_drv *ctx);
-int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *ctx);
-void intel_sst_clear_intr_mrfld(struct intel_sst_drv *ctx);
-
-int sst_load_fw(struct intel_sst_drv *ctx);
-int sst_load_library(struct snd_sst_lib_download *lib, u8 ops);
-void sst_post_download_mrfld(struct intel_sst_drv *ctx);
-int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx);
-void sst_memcpy_free_resources(struct intel_sst_drv *ctx);
-
-int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
-                               struct sst_block *block);
-int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
-                       struct sst_block *block);
-int sst_create_ipc_msg(struct ipc_post **arg, bool large);
-int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id);
-void sst_clean_stream(struct stream_info *stream);
-int intel_sst_register_compress(struct intel_sst_drv *sst);
-int intel_sst_remove_compress(struct intel_sst_drv *sst);
-void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id);
-int sst_send_sync_msg(int ipc, int str_id);
-int sst_get_num_channel(struct snd_sst_params *str_param);
-int sst_get_sfreq(struct snd_sst_params *str_param);
-int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params);
-void sst_restore_fw_context(void);
-struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
-                               u32 msg_id, u32 drv_id);
-int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large,
-               struct intel_sst_drv *sst_drv_ctx, struct sst_block **block,
-               u32 msg_id, u32 drv_id);
-int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed);
-int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
-               u32 drv_id, u32 ipc, void *data, u32 size);
-int sst_request_firmware_async(struct intel_sst_drv *ctx);
-int sst_driver_ops(struct intel_sst_drv *sst);
-struct sst_platform_info *sst_get_acpi_driver_data(const char *hid);
-void sst_firmware_load_cb(const struct firmware *fw, void *context);
-int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
-               int task_id, int ipc_msg, int cmd_id, int pipe_id,
-               size_t mbox_data_len, const void *mbox_data, void **data,
-               bool large, bool fill_dsp, bool sync, bool response);
-
-void sst_process_pending_msg(struct work_struct *work);
-int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx);
-void sst_init_stream(struct stream_info *stream,
-               int codec, int sst_id, int ops, u8 slot);
-int sst_validate_strid(struct intel_sst_drv *sst_drv_ctx, int str_id);
-struct stream_info *get_stream_info(struct intel_sst_drv *sst_drv_ctx,
-               int str_id);
-int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx,
-               u32 pipe_id);
-u32 relocate_imr_addr_mrfld(u32 base_addr);
-void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst,
-                                       struct ipc_post *msg);
-int sst_pm_runtime_put(struct intel_sst_drv *sst_drv);
-int sst_shim_write(void __iomem *addr, int offset, int value);
-u32 sst_shim_read(void __iomem *addr, int offset);
-u64 sst_reg_read64(void __iomem *addr, int offset);
-int sst_shim_write64(void __iomem *addr, int offset, u64 value);
-u64 sst_shim_read64(void __iomem *addr, int offset);
-void sst_set_fw_state_locked(
-               struct intel_sst_drv *sst_drv_ctx, int sst_state);
-void sst_fill_header_mrfld(union ipc_header_mrfld *header,
-                               int msg, int task_id, int large, int drv_id);
-void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg,
-                                       int pipe_id, int len);
-
-int sst_register(struct device *);
-int sst_unregister(struct device *);
-
-int sst_alloc_drv_context(struct intel_sst_drv **ctx,
-               struct device *dev, unsigned int dev_id);
-int sst_context_init(struct intel_sst_drv *ctx);
-void sst_context_cleanup(struct intel_sst_drv *ctx);
-void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
-#endif
diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c
deleted file mode 100644 (file)
index b782dfd..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * sst_acpi.c - SST (LPE) driver init file for ACPI enumeration.
- *
- * Copyright (c) 2013, Intel Corporation.
- *
- *  Authors:   Ramesh Babu K V <Ramesh.Babu@intel.com>
- *  Authors:   Omair Mohammed Abdullah <omair.m.abdullah@intel.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,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/firmware.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm_qos.h>
-#include <linux/acpi.h>
-#include <asm/platform_sst_audio.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include <acpi/acbuffer.h>
-#include <acpi/platform/acenv.h>
-#include <acpi/platform/aclinux.h>
-#include <acpi/actypes.h>
-#include <acpi/acpi_bus.h>
-#include "../sst-mfld-platform.h"
-#include "../sst-dsp.h"
-#include "sst.h"
-
-struct sst_machines {
-       char *codec_id;
-       char board[32];
-       char machine[32];
-       void (*machine_quirk)(void);
-       char firmware[FW_NAME_SIZE];
-       struct sst_platform_info *pdata;
-
-};
-
-/* LPE viewpoint addresses */
-#define SST_BYT_IRAM_PHY_START 0xff2c0000
-#define SST_BYT_IRAM_PHY_END   0xff2d4000
-#define SST_BYT_DRAM_PHY_START 0xff300000
-#define SST_BYT_DRAM_PHY_END   0xff320000
-#define SST_BYT_IMR_VIRT_START 0xc0000000 /* virtual addr in LPE */
-#define SST_BYT_IMR_VIRT_END   0xc01fffff
-#define SST_BYT_SHIM_PHY_ADDR  0xff340000
-#define SST_BYT_MBOX_PHY_ADDR  0xff344000
-#define SST_BYT_DMA0_PHY_ADDR  0xff298000
-#define SST_BYT_DMA1_PHY_ADDR  0xff29c000
-#define SST_BYT_SSP0_PHY_ADDR  0xff2a0000
-#define SST_BYT_SSP2_PHY_ADDR  0xff2a2000
-
-#define BYT_FW_MOD_TABLE_OFFSET        0x80000
-#define BYT_FW_MOD_TABLE_SIZE  0x100
-#define BYT_FW_MOD_OFFSET      (BYT_FW_MOD_TABLE_OFFSET + BYT_FW_MOD_TABLE_SIZE)
-
-static const struct sst_info byt_fwparse_info = {
-       .use_elf        = false,
-       .max_streams    = 25,
-       .iram_start     = SST_BYT_IRAM_PHY_START,
-       .iram_end       = SST_BYT_IRAM_PHY_END,
-       .iram_use       = true,
-       .dram_start     = SST_BYT_DRAM_PHY_START,
-       .dram_end       = SST_BYT_DRAM_PHY_END,
-       .dram_use       = true,
-       .imr_start      = SST_BYT_IMR_VIRT_START,
-       .imr_end        = SST_BYT_IMR_VIRT_END,
-       .imr_use        = true,
-       .mailbox_start  = SST_BYT_MBOX_PHY_ADDR,
-       .num_probes     = 0,
-       .lpe_viewpt_rqd  = true,
-};
-
-static const struct sst_ipc_info byt_ipc_info = {
-       .ipc_offset = 0,
-       .mbox_recv_off = 0x400,
-};
-
-static const struct sst_lib_dnld_info  byt_lib_dnld_info = {
-       .mod_base           = SST_BYT_IMR_VIRT_START,
-       .mod_end            = SST_BYT_IMR_VIRT_END,
-       .mod_table_offset   = BYT_FW_MOD_TABLE_OFFSET,
-       .mod_table_size     = BYT_FW_MOD_TABLE_SIZE,
-       .mod_ddr_dnld       = false,
-};
-
-static const struct sst_res_info byt_rvp_res_info = {
-       .shim_offset = 0x140000,
-       .shim_size = 0x000100,
-       .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
-       .ssp0_offset = 0xa0000,
-       .ssp0_size = 0x1000,
-       .dma0_offset = 0x98000,
-       .dma0_size = 0x4000,
-       .dma1_offset = 0x9c000,
-       .dma1_size = 0x4000,
-       .iram_offset = 0x0c0000,
-       .iram_size = 0x14000,
-       .dram_offset = 0x100000,
-       .dram_size = 0x28000,
-       .mbox_offset = 0x144000,
-       .mbox_size = 0x1000,
-       .acpi_lpe_res_index = 0,
-       .acpi_ddr_index = 2,
-       .acpi_ipc_irq_index = 5,
-};
-
-static struct sst_platform_info byt_rvp_platform_data = {
-       .probe_data = &byt_fwparse_info,
-       .ipc_info = &byt_ipc_info,
-       .lib_info = &byt_lib_dnld_info,
-       .res_info = &byt_rvp_res_info,
-       .platform = "sst-mfld-platform",
-};
-
-/* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail,
- * so pdata is same as Baytrail.
- */
-static struct sst_platform_info chv_platform_data = {
-       .probe_data = &byt_fwparse_info,
-       .ipc_info = &byt_ipc_info,
-       .lib_info = &byt_lib_dnld_info,
-       .res_info = &byt_rvp_res_info,
-       .platform = "sst-mfld-platform",
-};
-
-static int sst_platform_get_resources(struct intel_sst_drv *ctx)
-{
-       struct resource *rsrc;
-       struct platform_device *pdev = to_platform_device(ctx->dev);
-
-       /* All ACPI resource request here */
-       /* Get Shim addr */
-       rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
-                                       ctx->pdata->res_info->acpi_lpe_res_index);
-       if (!rsrc) {
-               dev_err(ctx->dev, "Invalid SHIM base from IFWI");
-               return -EIO;
-       }
-       dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start,
-                                       (unsigned int)resource_size(rsrc));
-
-       ctx->iram_base = rsrc->start + ctx->pdata->res_info->iram_offset;
-       ctx->iram_end =  ctx->iram_base + ctx->pdata->res_info->iram_size - 1;
-       dev_info(ctx->dev, "IRAM base: %#x", ctx->iram_base);
-       ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base,
-                                        ctx->pdata->res_info->iram_size);
-       if (!ctx->iram) {
-               dev_err(ctx->dev, "unable to map IRAM");
-               return -EIO;
-       }
-
-       ctx->dram_base = rsrc->start + ctx->pdata->res_info->dram_offset;
-       ctx->dram_end = ctx->dram_base + ctx->pdata->res_info->dram_size - 1;
-       dev_info(ctx->dev, "DRAM base: %#x", ctx->dram_base);
-       ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base,
-                                        ctx->pdata->res_info->dram_size);
-       if (!ctx->dram) {
-               dev_err(ctx->dev, "unable to map DRAM");
-               return -EIO;
-       }
-
-       ctx->shim_phy_add = rsrc->start + ctx->pdata->res_info->shim_offset;
-       dev_info(ctx->dev, "SHIM base: %#x", ctx->shim_phy_add);
-       ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add,
-                                       ctx->pdata->res_info->shim_size);
-       if (!ctx->shim) {
-               dev_err(ctx->dev, "unable to map SHIM");
-               return -EIO;
-       }
-
-       /* reassign physical address to LPE viewpoint address */
-       ctx->shim_phy_add = ctx->pdata->res_info->shim_phy_addr;
-
-       /* Get mailbox addr */
-       ctx->mailbox_add = rsrc->start + ctx->pdata->res_info->mbox_offset;
-       dev_info(ctx->dev, "Mailbox base: %#x", ctx->mailbox_add);
-       ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add,
-                                           ctx->pdata->res_info->mbox_size);
-       if (!ctx->mailbox) {
-               dev_err(ctx->dev, "unable to map mailbox");
-               return -EIO;
-       }
-
-       /* reassign physical address to LPE viewpoint address */
-       ctx->mailbox_add = ctx->info.mailbox_start;
-
-       rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
-                                       ctx->pdata->res_info->acpi_ddr_index);
-       if (!rsrc) {
-               dev_err(ctx->dev, "Invalid DDR base from IFWI");
-               return -EIO;
-       }
-       ctx->ddr_base = rsrc->start;
-       ctx->ddr_end = rsrc->end;
-       dev_info(ctx->dev, "DDR base: %#x", ctx->ddr_base);
-       ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base,
-                                       resource_size(rsrc));
-       if (!ctx->ddr) {
-               dev_err(ctx->dev, "unable to map DDR");
-               return -EIO;
-       }
-
-       /* Find the IRQ */
-       ctx->irq_num = platform_get_irq(pdev,
-                               ctx->pdata->res_info->acpi_ipc_irq_index);
-       return 0;
-}
-
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
-                                      void *context, void **ret)
-{
-       *(bool *)context = true;
-       return AE_OK;
-}
-
-static struct sst_machines *sst_acpi_find_machine(
-       struct sst_machines *machines)
-{
-       struct sst_machines *mach;
-       bool found = false;
-
-       for (mach = machines; mach->codec_id; mach++)
-               if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id,
-                                                 sst_acpi_mach_match,
-                                                 &found, NULL)) && found)
-                       return mach;
-
-       return NULL;
-}
-
-static int sst_acpi_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       int ret = 0;
-       struct intel_sst_drv *ctx;
-       const struct acpi_device_id *id;
-       struct sst_machines *mach;
-       struct platform_device *mdev;
-       struct platform_device *plat_dev;
-       unsigned int dev_id;
-
-       id = acpi_match_device(dev->driver->acpi_match_table, dev);
-       if (!id)
-               return -ENODEV;
-       dev_dbg(dev, "for %s", id->id);
-
-       mach = (struct sst_machines *)id->driver_data;
-       mach = sst_acpi_find_machine(mach);
-       if (mach == NULL) {
-               dev_err(dev, "No matching machine driver found\n");
-               return -ENODEV;
-       }
-
-       ret = kstrtouint(id->id, 16, &dev_id);
-       if (ret < 0) {
-               dev_err(dev, "Unique device id conversion error: %d\n", ret);
-               return ret;
-       }
-
-       dev_dbg(dev, "ACPI device id: %x\n", dev_id);
-
-       plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0);
-       if (IS_ERR(plat_dev)) {
-               dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform);
-               return PTR_ERR(plat_dev);
-       }
-
-       /* Create platform device for sst machine driver */
-       mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0);
-       if (IS_ERR(mdev)) {
-               dev_err(dev, "Failed to create machine device: %s\n", mach->machine);
-               return PTR_ERR(mdev);
-       }
-
-       ret = sst_alloc_drv_context(&ctx, dev, dev_id);
-       if (ret < 0)
-               return ret;
-
-       /* Fill sst platform data */
-       ctx->pdata = mach->pdata;
-       strcpy(ctx->firmware_name, mach->firmware);
-
-       ret = sst_platform_get_resources(ctx);
-       if (ret)
-               return ret;
-
-       ret = sst_context_init(ctx);
-       if (ret < 0)
-               return ret;
-
-       /* need to save shim registers in BYT */
-       ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64),
-                                       GFP_KERNEL);
-       if (!ctx->shim_regs64) {
-               return -ENOMEM;
-               goto do_sst_cleanup;
-       }
-
-       sst_configure_runtime_pm(ctx);
-       platform_set_drvdata(pdev, ctx);
-       return ret;
-
-do_sst_cleanup:
-       sst_context_cleanup(ctx);
-       platform_set_drvdata(pdev, NULL);
-       dev_err(ctx->dev, "failed with %d\n", ret);
-       return ret;
-}
-
-/**
-* intel_sst_remove - remove function
-*
-* @pdev:       platform device structure
-*
-* This function is called by OS when a device is unloaded
-* This frees the interrupt etc
-*/
-static int sst_acpi_remove(struct platform_device *pdev)
-{
-       struct intel_sst_drv *ctx;
-
-       ctx = platform_get_drvdata(pdev);
-       sst_context_cleanup(ctx);
-       platform_set_drvdata(pdev, NULL);
-       return 0;
-}
-
-static struct sst_machines sst_acpi_bytcr[] = {
-       {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin",
-                                               &byt_rvp_platform_data },
-       {},
-};
-
-/* Cherryview-based platforms: CherryTrail and Braswell */
-static struct sst_machines sst_acpi_chv[] = {
-       {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin",
-                                               &chv_platform_data },
-       {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
-                                               &chv_platform_data },
-       {},
-};
-
-static const struct acpi_device_id sst_acpi_ids[] = {
-       { "80860F28", (unsigned long)&sst_acpi_bytcr},
-       { "808622A8", (unsigned long) &sst_acpi_chv},
-       { },
-};
-
-MODULE_DEVICE_TABLE(acpi, sst_acpi_ids);
-
-static struct platform_driver sst_acpi_driver = {
-       .driver = {
-               .name                   = "intel_sst_acpi",
-               .acpi_match_table       = ACPI_PTR(sst_acpi_ids),
-               .pm                     = &intel_sst_pm,
-       },
-       .probe  = sst_acpi_probe,
-       .remove = sst_acpi_remove,
-};
-
-module_platform_driver(sst_acpi_driver);
-
-MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine ACPI Driver");
-MODULE_AUTHOR("Ramesh Babu K V");
-MODULE_AUTHOR("Omair Mohammed Abdullah");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("sst");
diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c
deleted file mode 100644 (file)
index 5f75ef3..0000000
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- *  sst_drv_interface.c - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-14 Intel Corp
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com)
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/firmware.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm_qos.h>
-#include <linux/math64.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include <asm/platform_sst_audio.h>
-#include "../sst-mfld-platform.h"
-#include "sst.h"
-#include "../sst-dsp.h"
-
-
-
-#define NUM_CODEC 2
-#define MIN_FRAGMENT 2
-#define MAX_FRAGMENT 4
-#define MIN_FRAGMENT_SIZE (50 * 1024)
-#define MAX_FRAGMENT_SIZE (1024 * 1024)
-#define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz)  (((pcm_wd_sz + 15) >> 4) << 1)
-
-int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id)
-{
-       struct stream_info *stream;
-       int ret = 0;
-
-       stream = get_stream_info(ctx, str_id);
-       if (stream) {
-               /* str_id is valid, so stream is alloacted */
-               ret = sst_free_stream(ctx, str_id);
-               if (ret)
-                       sst_clean_stream(&ctx->streams[str_id]);
-               return ret;
-       } else {
-               dev_err(ctx->dev, "we tried to free stream context %d which was freed!!!\n", str_id);
-       }
-       return ret;
-}
-
-int sst_get_stream_allocated(struct intel_sst_drv *ctx,
-       struct snd_sst_params *str_param,
-       struct snd_sst_lib_download **lib_dnld)
-{
-       int retval;
-
-       retval = ctx->ops->alloc_stream(ctx, str_param);
-       if (retval > 0)
-               dev_dbg(ctx->dev, "Stream allocated %d\n", retval);
-       return retval;
-
-}
-
-/*
- * sst_get_sfreq - this function returns the frequency of the stream
- *
- * @str_param : stream params
- */
-int sst_get_sfreq(struct snd_sst_params *str_param)
-{
-       switch (str_param->codec) {
-       case SST_CODEC_TYPE_PCM:
-               return str_param->sparams.uc.pcm_params.sfreq;
-       case SST_CODEC_TYPE_AAC:
-               return str_param->sparams.uc.aac_params.externalsr;
-       case SST_CODEC_TYPE_MP3:
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-/*
- * sst_get_num_channel - get number of channels for the stream
- *
- * @str_param : stream params
- */
-int sst_get_num_channel(struct snd_sst_params *str_param)
-{
-       switch (str_param->codec) {
-       case SST_CODEC_TYPE_PCM:
-               return str_param->sparams.uc.pcm_params.num_chan;
-       case SST_CODEC_TYPE_MP3:
-               return str_param->sparams.uc.mp3_params.num_chan;
-       case SST_CODEC_TYPE_AAC:
-               return str_param->sparams.uc.aac_params.num_chan;
-       default:
-               return -EINVAL;
-       }
-}
-
-/*
- * sst_get_stream - this function prepares for stream allocation
- *
- * @str_param : stream param
- */
-int sst_get_stream(struct intel_sst_drv *ctx,
-                       struct snd_sst_params *str_param)
-{
-       int retval;
-       struct stream_info *str_info;
-
-       /* stream is not allocated, we are allocating */
-       retval = ctx->ops->alloc_stream(ctx, str_param);
-       if (retval <= 0) {
-               return -EIO;
-       }
-       /* store sampling freq */
-       str_info = &ctx->streams[retval];
-       str_info->sfreq = sst_get_sfreq(str_param);
-
-       return retval;
-}
-
-static int sst_power_control(struct device *dev, bool state)
-{
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       dev_dbg(ctx->dev, "state:%d", state);
-       if (state == true)
-               return pm_runtime_get_sync(dev);
-       else
-               return sst_pm_runtime_put(ctx);
-}
-
-/*
- * sst_open_pcm_stream - Open PCM interface
- *
- * @str_param: parameters of pcm stream
- *
- * This function is called by MID sound card driver to open
- * a new pcm interface
- */
-static int sst_open_pcm_stream(struct device *dev,
-               struct snd_sst_params *str_param)
-{
-       int retval;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       if (!str_param)
-               return -EINVAL;
-
-       retval = sst_get_stream(ctx, str_param);
-       if (retval > 0)
-               ctx->stream_cnt++;
-       else
-               dev_err(ctx->dev, "sst_get_stream returned err %d\n", retval);
-
-       return retval;
-}
-
-static int sst_cdev_open(struct device *dev,
-               struct snd_sst_params *str_params, struct sst_compress_cb *cb)
-{
-       int str_id, retval;
-       struct stream_info *stream;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       retval = pm_runtime_get_sync(ctx->dev);
-       if (retval < 0)
-               return retval;
-
-       str_id = sst_get_stream(ctx, str_params);
-       if (str_id > 0) {
-               dev_dbg(dev, "stream allocated in sst_cdev_open %d\n", str_id);
-               stream = &ctx->streams[str_id];
-               stream->compr_cb = cb->compr_cb;
-               stream->compr_cb_param = cb->param;
-               stream->drain_notify = cb->drain_notify;
-               stream->drain_cb_param = cb->drain_cb_param;
-       } else {
-               dev_err(dev, "stream encountered error during alloc %d\n", str_id);
-               str_id = -EINVAL;
-               sst_pm_runtime_put(ctx);
-       }
-       return str_id;
-}
-
-static int sst_cdev_close(struct device *dev, unsigned int str_id)
-{
-       int retval;
-       struct stream_info *stream;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       stream = get_stream_info(ctx, str_id);
-       if (!stream) {
-               dev_err(dev, "stream info is NULL for str %d!!!\n", str_id);
-               return -EINVAL;
-       }
-
-       if (stream->status == STREAM_RESET) {
-               dev_dbg(dev, "stream in reset state...\n");
-               stream->status = STREAM_UN_INIT;
-
-               retval = 0;
-               goto put;
-       }
-
-       retval = sst_free_stream(ctx, str_id);
-put:
-       stream->compr_cb_param = NULL;
-       stream->compr_cb = NULL;
-
-       if (retval)
-               dev_err(dev, "free stream returned err %d\n", retval);
-
-       dev_dbg(dev, "End\n");
-       return retval;
-
-}
-
-static int sst_cdev_ack(struct device *dev, unsigned int str_id,
-               unsigned long bytes)
-{
-       struct stream_info *stream;
-       struct snd_sst_tstamp fw_tstamp = {0,};
-       int offset;
-       void __iomem *addr;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       stream = get_stream_info(ctx, str_id);
-       if (!stream)
-               return -EINVAL;
-
-       /* update bytes sent */
-       stream->cumm_bytes += bytes;
-       dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes);
-
-       memcpy_fromio(&fw_tstamp,
-               ((void *)(ctx->mailbox + ctx->tstamp)
-               +(str_id * sizeof(fw_tstamp))),
-               sizeof(fw_tstamp));
-
-       fw_tstamp.bytes_copied = stream->cumm_bytes;
-       dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n",
-                       fw_tstamp.bytes_copied, bytes);
-
-       addr =  ((void *)(ctx->mailbox + ctx->tstamp)) +
-                       (str_id * sizeof(fw_tstamp));
-       offset =  offsetof(struct snd_sst_tstamp, bytes_copied);
-       sst_shim_write(addr, offset, fw_tstamp.bytes_copied);
-       return 0;
-}
-
-static int sst_cdev_set_metadata(struct device *dev,
-               unsigned int str_id, struct snd_compr_metadata *metadata)
-{
-       int retval = 0;
-       struct stream_info *str_info;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "set metadata for stream %d\n", str_id);
-
-       str_info = get_stream_info(ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-
-       dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id);
-       retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD,
-                       IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id,
-                       sizeof(*metadata), metadata, NULL,
-                       true, true, true, false);
-
-       return retval;
-}
-
-static int sst_cdev_stream_pause(struct device *dev, unsigned int str_id)
-{
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       return sst_pause_stream(ctx, str_id);
-}
-
-static int sst_cdev_stream_pause_release(struct device *dev,
-               unsigned int str_id)
-{
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       return sst_resume_stream(ctx, str_id);
-}
-
-static int sst_cdev_stream_start(struct device *dev, unsigned int str_id)
-{
-       struct stream_info *str_info;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       str_info = get_stream_info(ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-       str_info->prev = str_info->status;
-       str_info->status = STREAM_RUNNING;
-       return sst_start_stream(ctx, str_id);
-}
-
-static int sst_cdev_stream_drop(struct device *dev, unsigned int str_id)
-{
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       return sst_drop_stream(ctx, str_id);
-}
-
-static int sst_cdev_stream_drain(struct device *dev, unsigned int str_id)
-{
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       return sst_drain_stream(ctx, str_id, false);
-}
-
-static int sst_cdev_stream_partial_drain(struct device *dev,
-               unsigned int str_id)
-{
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       return sst_drain_stream(ctx, str_id, true);
-}
-
-static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
-               struct snd_compr_tstamp *tstamp)
-{
-       struct snd_sst_tstamp fw_tstamp = {0,};
-       struct stream_info *stream;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       memcpy_fromio(&fw_tstamp,
-               ((void *)(ctx->mailbox + ctx->tstamp)
-               +(str_id * sizeof(fw_tstamp))),
-               sizeof(fw_tstamp));
-
-       stream = get_stream_info(ctx, str_id);
-       if (!stream)
-               return -EINVAL;
-       dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter);
-
-       tstamp->copied_total = fw_tstamp.ring_buffer_counter;
-       tstamp->pcm_frames = fw_tstamp.frames_decoded;
-       tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter,
-                       (u64)((stream->num_ch) * SST_GET_BYTES_PER_SAMPLE(24)));
-       tstamp->sampling_rate = fw_tstamp.sampling_frequency;
-
-       dev_dbg(dev, "PCM  = %u\n", tstamp->pcm_io_frames);
-       dev_dbg(dev, "Ptr Query on strid = %d  copied_total %d, decodec %d\n",
-               str_id, tstamp->copied_total, tstamp->pcm_frames);
-       dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames);
-
-       return 0;
-}
-
-static int sst_cdev_caps(struct snd_compr_caps *caps)
-{
-       caps->num_codecs = NUM_CODEC;
-       caps->min_fragment_size = MIN_FRAGMENT_SIZE;  /* 50KB */
-       caps->max_fragment_size = MAX_FRAGMENT_SIZE;  /* 1024KB */
-       caps->min_fragments = MIN_FRAGMENT;
-       caps->max_fragments = MAX_FRAGMENT;
-       caps->codecs[0] = SND_AUDIOCODEC_MP3;
-       caps->codecs[1] = SND_AUDIOCODEC_AAC;
-       return 0;
-}
-
-static struct snd_compr_codec_caps caps_mp3 = {
-       .num_descriptors = 1,
-       .descriptor[0].max_ch = 2,
-       .descriptor[0].sample_rates[0] = 48000,
-       .descriptor[0].sample_rates[1] = 44100,
-       .descriptor[0].sample_rates[2] = 32000,
-       .descriptor[0].sample_rates[3] = 16000,
-       .descriptor[0].sample_rates[4] = 8000,
-       .descriptor[0].num_sample_rates = 5,
-       .descriptor[0].bit_rate[0] = 320,
-       .descriptor[0].bit_rate[1] = 192,
-       .descriptor[0].num_bitrates = 2,
-       .descriptor[0].profiles = 0,
-       .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
-       .descriptor[0].formats = 0,
-};
-
-static struct snd_compr_codec_caps caps_aac = {
-       .num_descriptors = 2,
-       .descriptor[1].max_ch = 2,
-       .descriptor[0].sample_rates[0] = 48000,
-       .descriptor[0].sample_rates[1] = 44100,
-       .descriptor[0].sample_rates[2] = 32000,
-       .descriptor[0].sample_rates[3] = 16000,
-       .descriptor[0].sample_rates[4] = 8000,
-       .descriptor[0].num_sample_rates = 5,
-       .descriptor[1].bit_rate[0] = 320,
-       .descriptor[1].bit_rate[1] = 192,
-       .descriptor[1].num_bitrates = 2,
-       .descriptor[1].profiles = 0,
-       .descriptor[1].modes = 0,
-       .descriptor[1].formats =
-                       (SND_AUDIOSTREAMFORMAT_MP4ADTS |
-                               SND_AUDIOSTREAMFORMAT_RAW),
-};
-
-static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec)
-{
-       if (codec->codec == SND_AUDIOCODEC_MP3)
-               *codec = caps_mp3;
-       else if (codec->codec == SND_AUDIOCODEC_AAC)
-               *codec = caps_aac;
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
-void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id)
-{
-       struct stream_info *stream;
-
-       dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n",
-                       str_id);
-       stream = &ctx->streams[str_id];
-       if (stream->compr_cb)
-               stream->compr_cb(stream->compr_cb_param);
-}
-
-/*
- * sst_close_pcm_stream - Close PCM interface
- *
- * @str_id: stream id to be closed
- *
- * This function is called by MID sound card driver to close
- * an existing pcm interface
- */
-static int sst_close_pcm_stream(struct device *dev, unsigned int str_id)
-{
-       struct stream_info *stream;
-       int retval = 0;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       stream = get_stream_info(ctx, str_id);
-       if (!stream) {
-               dev_err(ctx->dev, "stream info is NULL for str %d!!!\n", str_id);
-               return -EINVAL;
-       }
-
-       if (stream->status == STREAM_RESET) {
-               /* silently fail here as we have cleaned the stream earlier */
-               dev_dbg(ctx->dev, "stream in reset state...\n");
-
-               retval = 0;
-               goto put;
-       }
-
-       retval = free_stream_context(ctx, str_id);
-put:
-       stream->pcm_substream = NULL;
-       stream->status = STREAM_UN_INIT;
-       stream->period_elapsed = NULL;
-       ctx->stream_cnt--;
-
-       if (retval)
-               dev_err(ctx->dev, "free stream returned err %d\n", retval);
-
-       dev_dbg(ctx->dev, "Exit\n");
-       return 0;
-}
-
-static inline int sst_calc_tstamp(struct intel_sst_drv *ctx,
-               struct pcm_stream_info *info,
-               struct snd_pcm_substream *substream,
-               struct snd_sst_tstamp *fw_tstamp)
-{
-       size_t delay_bytes, delay_frames;
-       size_t buffer_sz;
-       u32 pointer_bytes, pointer_samples;
-
-       dev_dbg(ctx->dev, "mrfld ring_buffer_counter %llu in bytes\n",
-                       fw_tstamp->ring_buffer_counter);
-       dev_dbg(ctx->dev, "mrfld hardware_counter %llu in bytes\n",
-                        fw_tstamp->hardware_counter);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               delay_bytes = (size_t) (fw_tstamp->ring_buffer_counter -
-                                       fw_tstamp->hardware_counter);
-       else
-               delay_bytes = (size_t) (fw_tstamp->hardware_counter -
-                                       fw_tstamp->ring_buffer_counter);
-       delay_frames = bytes_to_frames(substream->runtime, delay_bytes);
-       buffer_sz = snd_pcm_lib_buffer_bytes(substream);
-       div_u64_rem(fw_tstamp->ring_buffer_counter, buffer_sz, &pointer_bytes);
-       pointer_samples = bytes_to_samples(substream->runtime, pointer_bytes);
-
-       dev_dbg(ctx->dev, "pcm delay %zu in bytes\n", delay_bytes);
-
-       info->buffer_ptr = pointer_samples / substream->runtime->channels;
-
-       info->pcm_delay = delay_frames / substream->runtime->channels;
-       dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n",
-                       info->buffer_ptr, info->pcm_delay);
-       return 0;
-}
-
-static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info)
-{
-       struct stream_info *stream;
-       struct snd_pcm_substream *substream;
-       struct snd_sst_tstamp fw_tstamp;
-       unsigned int str_id;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       str_id = info->str_id;
-       stream = get_stream_info(ctx, str_id);
-       if (!stream)
-               return -EINVAL;
-
-       if (!stream->pcm_substream)
-               return -EINVAL;
-       substream = stream->pcm_substream;
-
-       memcpy_fromio(&fw_tstamp,
-               ((void *)(ctx->mailbox + ctx->tstamp)
-                       + (str_id * sizeof(fw_tstamp))),
-               sizeof(fw_tstamp));
-       return sst_calc_tstamp(ctx, info, substream, &fw_tstamp);
-}
-
-static int sst_stream_start(struct device *dev, int str_id)
-{
-       struct stream_info *str_info;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       if (ctx->sst_state != SST_FW_RUNNING)
-               return 0;
-       str_info = get_stream_info(ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-       str_info->prev = str_info->status;
-       str_info->status = STREAM_RUNNING;
-       sst_start_stream(ctx, str_id);
-
-       return 0;
-}
-
-static int sst_stream_drop(struct device *dev, int str_id)
-{
-       struct stream_info *str_info;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       if (ctx->sst_state != SST_FW_RUNNING)
-               return 0;
-
-       str_info = get_stream_info(ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-       str_info->prev = STREAM_UN_INIT;
-       str_info->status = STREAM_INIT;
-       return sst_drop_stream(ctx, str_id);
-}
-
-static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info)
-{
-       int str_id = 0;
-       struct stream_info *stream;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       str_id = str_info->str_id;
-
-       if (ctx->sst_state != SST_FW_RUNNING)
-               return 0;
-
-       stream = get_stream_info(ctx, str_id);
-       if (!stream)
-               return -EINVAL;
-
-       dev_dbg(ctx->dev, "setting the period ptrs\n");
-       stream->pcm_substream = str_info->arg;
-       stream->period_elapsed = str_info->period_elapsed;
-       stream->sfreq = str_info->sfreq;
-       stream->prev = stream->status;
-       stream->status = STREAM_INIT;
-       dev_dbg(ctx->dev,
-               "pcm_substream %p, period_elapsed %p, sfreq %d, status %d\n",
-               stream->pcm_substream, stream->period_elapsed,
-               stream->sfreq, stream->status);
-
-       return 0;
-}
-
-/*
- * sst_set_byte_stream - Set generic params
- *
- * @cmd: control cmd to be set
- * @arg: command argument
- *
- * This function is called by MID sound card driver to configure
- * SST runtime params.
- */
-static int sst_send_byte_stream(struct device *dev,
-               struct snd_sst_bytes_v2 *bytes)
-{
-       int ret_val = 0;
-       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       if (NULL == bytes)
-               return -EINVAL;
-       ret_val = pm_runtime_get_sync(ctx->dev);
-       if (ret_val < 0)
-               return ret_val;
-
-       ret_val = sst_send_byte_stream_mrfld(ctx, bytes);
-       sst_pm_runtime_put(ctx);
-
-       return ret_val;
-}
-
-static struct sst_ops pcm_ops = {
-       .open = sst_open_pcm_stream,
-       .stream_init = sst_stream_init,
-       .stream_start = sst_stream_start,
-       .stream_drop = sst_stream_drop,
-       .stream_read_tstamp = sst_read_timestamp,
-       .send_byte_stream = sst_send_byte_stream,
-       .close = sst_close_pcm_stream,
-       .power = sst_power_control,
-};
-
-static struct compress_sst_ops compr_ops = {
-       .open = sst_cdev_open,
-       .close = sst_cdev_close,
-       .stream_pause = sst_cdev_stream_pause,
-       .stream_pause_release = sst_cdev_stream_pause_release,
-       .stream_start = sst_cdev_stream_start,
-       .stream_drop = sst_cdev_stream_drop,
-       .stream_drain = sst_cdev_stream_drain,
-       .stream_partial_drain = sst_cdev_stream_partial_drain,
-       .tstamp = sst_cdev_tstamp,
-       .ack = sst_cdev_ack,
-       .get_caps = sst_cdev_caps,
-       .get_codec_caps = sst_cdev_codec_caps,
-       .set_metadata = sst_cdev_set_metadata,
-       .power = sst_power_control,
-};
-
-static struct sst_device sst_dsp_device = {
-       .name = "Intel(R) SST LPE",
-       .dev = NULL,
-       .ops = &pcm_ops,
-       .compr_ops = &compr_ops,
-};
-
-/*
- * sst_register - function to register DSP
- *
- * This functions registers DSP with the platform driver
- */
-int sst_register(struct device *dev)
-{
-       int ret_val;
-
-       sst_dsp_device.dev = dev;
-       ret_val = sst_register_dsp(&sst_dsp_device);
-       if (ret_val)
-               dev_err(dev, "Unable to register DSP with platform driver\n");
-
-       return ret_val;
-}
-
-int sst_unregister(struct device *dev)
-{
-       return sst_unregister_dsp(&sst_dsp_device);
-}
diff --git a/sound/soc/intel/sst/sst_ipc.c b/sound/soc/intel/sst/sst_ipc.c
deleted file mode 100644 (file)
index 484e609..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- *  sst_ipc.c - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-14 Intel Corporation
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com>
- *             KP Jeeja <jeeja.kp@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/pci.h>
-#include <linux/firmware.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include <asm/intel-mid.h>
-#include <asm/platform_sst_audio.h>
-#include "../sst-mfld-platform.h"
-#include "sst.h"
-#include "../sst-dsp.h"
-
-struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
-                                       u32 msg_id, u32 drv_id)
-{
-       struct sst_block *msg = NULL;
-
-       dev_dbg(ctx->dev, "Enter\n");
-       msg = kzalloc(sizeof(*msg), GFP_KERNEL);
-       if (!msg)
-               return NULL;
-       msg->condition = false;
-       msg->on = true;
-       msg->msg_id = msg_id;
-       msg->drv_id = drv_id;
-       spin_lock_bh(&ctx->block_lock);
-       list_add_tail(&msg->node, &ctx->block_list);
-       spin_unlock_bh(&ctx->block_lock);
-
-       return msg;
-}
-
-/*
- * while handling the interrupts, we need to check for message status and
- * then if we are blocking for a message
- *
- * here we are unblocking the blocked ones, this is based on id we have
- * passed and search that for block threads.
- * We will not find block in two cases
- *  a) when its small message and block in not there, so silently ignore
- *  them
- *  b) when we are actually not able to find the block (bug perhaps)
- *
- *  Since we have bit of small messages we can spam kernel log with err
- *  print on above so need to keep as debug prints which should be enabled
- *  via dynamic debug while debugging IPC issues
- */
-int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
-               u32 drv_id, u32 ipc, void *data, u32 size)
-{
-       struct sst_block *block = NULL;
-
-       dev_dbg(ctx->dev, "Enter\n");
-
-       spin_lock_bh(&ctx->block_lock);
-       list_for_each_entry(block, &ctx->block_list, node) {
-               dev_dbg(ctx->dev, "Block ipc %d, drv_id %d\n", block->msg_id,
-                                                       block->drv_id);
-               if (block->msg_id == ipc && block->drv_id == drv_id) {
-                       dev_dbg(ctx->dev, "free up the block\n");
-                       block->ret_code = result;
-                       block->data = data;
-                       block->size = size;
-                       block->condition = true;
-                       spin_unlock_bh(&ctx->block_lock);
-                       wake_up(&ctx->wait_queue);
-                       return 0;
-               }
-       }
-       spin_unlock_bh(&ctx->block_lock);
-       dev_dbg(ctx->dev,
-               "Block not found or a response received for a short msg for ipc %d, drv_id %d\n",
-               ipc, drv_id);
-       return -EINVAL;
-}
-
-int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed)
-{
-       struct sst_block *block = NULL, *__block;
-
-       dev_dbg(ctx->dev, "Enter\n");
-       spin_lock_bh(&ctx->block_lock);
-       list_for_each_entry_safe(block, __block, &ctx->block_list, node) {
-               if (block == freed) {
-                       pr_debug("pvt_id freed --> %d\n", freed->drv_id);
-                       /* toggle the index position of pvt_id */
-                       list_del(&freed->node);
-                       spin_unlock_bh(&ctx->block_lock);
-                       kfree(freed->data);
-                       freed->data = NULL;
-                       kfree(freed);
-                       return 0;
-               }
-       }
-       spin_unlock_bh(&ctx->block_lock);
-       dev_err(ctx->dev, "block is already freed!!!\n");
-       return -EINVAL;
-}
-
-int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx,
-               struct ipc_post *ipc_msg, bool sync)
-{
-       struct ipc_post *msg = ipc_msg;
-       union ipc_header_mrfld header;
-       unsigned int loop_count = 0;
-       int retval = 0;
-       unsigned long irq_flags;
-
-       dev_dbg(sst_drv_ctx->dev, "Enter: sync: %d\n", sync);
-       spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
-       header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX);
-       if (sync) {
-               while (header.p.header_high.part.busy) {
-                       if (loop_count > 25) {
-                               dev_err(sst_drv_ctx->dev,
-                                       "sst: Busy wait failed, cant send this msg\n");
-                               retval = -EBUSY;
-                               goto out;
-                       }
-                       cpu_relax();
-                       loop_count++;
-                       header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX);
-               }
-       } else {
-               if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) {
-                       /* queue is empty, nothing to send */
-                       spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
-                       dev_dbg(sst_drv_ctx->dev,
-                                       "Empty msg queue... NO Action\n");
-                       return 0;
-               }
-
-               if (header.p.header_high.part.busy) {
-                       spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
-                       dev_dbg(sst_drv_ctx->dev, "Busy not free... post later\n");
-                       return 0;
-               }
-
-               /* copy msg from list */
-               msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next,
-                               struct ipc_post, node);
-               list_del(&msg->node);
-       }
-       dev_dbg(sst_drv_ctx->dev, "sst: Post message: header = %x\n",
-                               msg->mrfld_header.p.header_high.full);
-       dev_dbg(sst_drv_ctx->dev, "sst: size = 0x%x\n",
-                       msg->mrfld_header.p.header_low_payload);
-
-       if (msg->mrfld_header.p.header_high.part.large)
-               memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
-                       msg->mailbox_data,
-                       msg->mrfld_header.p.header_low_payload);
-
-       sst_shim_write64(sst_drv_ctx->shim, SST_IPCX, msg->mrfld_header.full);
-
-out:
-       spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
-       kfree(msg->mailbox_data);
-       kfree(msg);
-       return retval;
-}
-
-void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
-{
-       union interrupt_reg_mrfld isr;
-       union interrupt_reg_mrfld imr;
-       union ipc_header_mrfld clear_ipc;
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
-       imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX);
-       isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX);
-
-       /* write 1 to clear*/
-       isr.part.busy_interrupt = 1;
-       sst_shim_write64(sst_drv_ctx->shim, SST_ISRX, isr.full);
-
-       /* Set IA done bit */
-       clear_ipc.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCD);
-
-       clear_ipc.p.header_high.part.busy = 0;
-       clear_ipc.p.header_high.part.done = 1;
-       clear_ipc.p.header_low_payload = IPC_ACK_SUCCESS;
-       sst_shim_write64(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full);
-       /* un mask busy interrupt */
-       imr.part.busy_interrupt = 0;
-       sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full);
-       spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
-}
-
-
-/*
- * process_fw_init - process the FW init msg
- *
- * @msg: IPC message mailbox data from FW
- *
- * This function processes the FW init msg from FW
- * marks FW state and prints debug info of loaded FW
- */
-static void process_fw_init(struct intel_sst_drv *sst_drv_ctx,
-                       void *msg)
-{
-       struct ipc_header_fw_init *init =
-               (struct ipc_header_fw_init *)msg;
-       int retval = 0;
-
-       dev_dbg(sst_drv_ctx->dev, "*** FW Init msg came***\n");
-       if (init->result) {
-               sst_set_fw_state_locked(sst_drv_ctx, SST_RESET);
-               dev_err(sst_drv_ctx->dev, "FW Init failed, Error %x\n",
-                               init->result);
-               retval = init->result;
-               goto ret;
-       }
-
-ret:
-       sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0);
-}
-
-static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx,
-                       struct ipc_post *msg)
-{
-       u32 msg_id;
-       int str_id;
-       u32 data_size, i;
-       void *data_offset;
-       struct stream_info *stream;
-       union ipc_header_high msg_high;
-       u32 msg_low, pipe_id;
-
-       msg_high = msg->mrfld_header.p.header_high;
-       msg_low = msg->mrfld_header.p.header_low_payload;
-       msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id;
-       data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr));
-       data_size =  msg_low - (sizeof(struct ipc_dsp_hdr));
-
-       switch (msg_id) {
-       case IPC_SST_PERIOD_ELAPSED_MRFLD:
-               pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
-               str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
-               if (str_id > 0) {
-                       dev_dbg(sst_drv_ctx->dev,
-                               "Period elapsed rcvd for pipe id 0x%x\n",
-                               pipe_id);
-                       stream = &sst_drv_ctx->streams[str_id];
-                       if (stream->period_elapsed)
-                               stream->period_elapsed(stream->pcm_substream);
-                       if (stream->compr_cb)
-                               stream->compr_cb(stream->compr_cb_param);
-               }
-               break;
-
-       case IPC_IA_DRAIN_STREAM_MRFLD:
-               pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
-               str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
-               if (str_id > 0) {
-                       stream = &sst_drv_ctx->streams[str_id];
-                       if (stream->drain_notify)
-                               stream->drain_notify(stream->drain_cb_param);
-               }
-               break;
-
-       case IPC_IA_FW_ASYNC_ERR_MRFLD:
-               dev_err(sst_drv_ctx->dev, "FW sent async error msg:\n");
-               for (i = 0; i < (data_size/4); i++)
-                       print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE,
-                                       16, 4, data_offset, data_size, false);
-               break;
-
-       case IPC_IA_FW_INIT_CMPLT_MRFLD:
-               process_fw_init(sst_drv_ctx, data_offset);
-               break;
-
-       case IPC_IA_BUF_UNDER_RUN_MRFLD:
-               pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
-               str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
-               if (str_id > 0)
-                       dev_err(sst_drv_ctx->dev,
-                               "Buffer under-run for pipe:%#x str_id:%d\n",
-                               pipe_id, str_id);
-               break;
-
-       default:
-               dev_err(sst_drv_ctx->dev,
-                       "Unrecognized async msg from FW msg_id %#x\n", msg_id);
-       }
-}
-
-void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
-               struct ipc_post *msg)
-{
-       unsigned int drv_id;
-       void *data;
-       union ipc_header_high msg_high;
-       u32 msg_low;
-       struct ipc_dsp_hdr *dsp_hdr;
-       unsigned int cmd_id;
-
-       msg_high = msg->mrfld_header.p.header_high;
-       msg_low = msg->mrfld_header.p.header_low_payload;
-
-       dev_dbg(sst_drv_ctx->dev, "IPC process message header %x payload %x\n",
-                       msg->mrfld_header.p.header_high.full,
-                       msg->mrfld_header.p.header_low_payload);
-
-       drv_id = msg_high.part.drv_id;
-
-       /* Check for async messages first */
-       if (drv_id == SST_ASYNC_DRV_ID) {
-               /*FW sent async large message*/
-               process_fw_async_msg(sst_drv_ctx, msg);
-               return;
-       }
-
-       /* FW sent short error response for an IPC */
-       if (msg_high.part.result && drv_id && !msg_high.part.large) {
-               /* 32-bit FW error code in msg_low */
-               dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low);
-               sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
-                       msg_high.part.drv_id,
-                       msg_high.part.msg_id, NULL, 0);
-               return;
-       }
-
-       /*
-        * Process all valid responses
-        * if it is a large message, the payload contains the size to
-        * copy from mailbox
-        **/
-       if (msg_high.part.large) {
-               data = kzalloc(msg_low, GFP_KERNEL);
-               if (!data)
-                       return;
-               memcpy(data, (void *) msg->mailbox_data, msg_low);
-               /* Copy command id so that we can use to put sst to reset */
-               dsp_hdr = (struct ipc_dsp_hdr *)data;
-               cmd_id = dsp_hdr->cmd_id;
-               dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id);
-               if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
-                               msg_high.part.drv_id,
-                               msg_high.part.msg_id, data, msg_low))
-                       kfree(data);
-       } else {
-               sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
-                               msg_high.part.drv_id,
-                               msg_high.part.msg_id, NULL, 0);
-       }
-
-}
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c
deleted file mode 100644 (file)
index 7888cd7..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- *  sst_dsp.c - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-14      Intel Corp
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com>
- *             KP Jeeja <jeeja.kp@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This file contains all dsp controlling functions like firmware download,
- * setting/resetting dsp cores, etc
- */
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/firmware.h>
-#include <linux/dmaengine.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm_qos.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include <asm/platform_sst_audio.h>
-#include "../sst-mfld-platform.h"
-#include "sst.h"
-#include "../sst-dsp.h"
-
-static inline void memcpy32_toio(void __iomem *dst, const void *src, int count)
-{
-       /* __iowrite32_copy uses 32-bit count values so divide by 4 for
-        * right count in words
-        */
-       __iowrite32_copy(dst, src, count/4);
-}
-
-/**
- * intel_sst_reset_dsp_mrfld - Resetting SST DSP
- *
- * This resets DSP in case of MRFLD platfroms
- */
-int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx)
-{
-       union config_status_reg_mrfld csr;
-
-       dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n");
-       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
-
-       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
-
-       csr.full |= 0x7;
-       sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
-       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
-
-       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
-
-       csr.full &= ~(0x1);
-       sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
-
-       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
-       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
-       return 0;
-}
-
-/**
- * sst_start_merrifield - Start the SST DSP processor
- *
- * This starts the DSP in MERRIFIELD platfroms
- */
-int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx)
-{
-       union config_status_reg_mrfld csr;
-
-       dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n");
-       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
-       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
-
-       csr.full |= 0x7;
-       sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
-
-       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
-       dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
-
-       csr.part.xt_snoop = 1;
-       csr.full &= ~(0x5);
-       sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
-
-       csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
-       dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n",
-                       csr.full);
-       return 0;
-}
-
-static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size,
-               struct fw_module_header **module, u32 *num_modules)
-{
-       struct sst_fw_header *header;
-       const void *sst_fw_in_mem = ctx->fw_in_mem;
-
-       dev_dbg(ctx->dev, "Enter\n");
-
-       /* Read the header information from the data pointer */
-       header = (struct sst_fw_header *)sst_fw_in_mem;
-       dev_dbg(ctx->dev,
-               "header sign=%s size=%x modules=%x fmt=%x size=%zx\n",
-               header->signature, header->file_size, header->modules,
-               header->file_format, sizeof(*header));
-
-       /* verify FW */
-       if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
-               (size != header->file_size + sizeof(*header))) {
-               /* Invalid FW signature */
-               dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n");
-               return -EINVAL;
-       }
-       *num_modules = header->modules;
-       *module = (void *)sst_fw_in_mem + sizeof(*header);
-
-       return 0;
-}
-
-/*
- * sst_fill_memcpy_list - Fill the memcpy list
- *
- * @memcpy_list: List to be filled
- * @destn: Destination addr to be filled in the list
- * @src: Source addr to be filled in the list
- * @size: Size to be filled in the list
- *
- * Adds the node to the list after required fields
- * are populated in the node
- */
-static int sst_fill_memcpy_list(struct list_head *memcpy_list,
-                       void *destn, const void *src, u32 size, bool is_io)
-{
-       struct sst_memcpy_list *listnode;
-
-       listnode = kzalloc(sizeof(*listnode), GFP_KERNEL);
-       if (listnode == NULL)
-               return -ENOMEM;
-       listnode->dstn = destn;
-       listnode->src = src;
-       listnode->size = size;
-       listnode->is_io = is_io;
-       list_add_tail(&listnode->memcpylist, memcpy_list);
-
-       return 0;
-}
-
-/**
- * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list
- *
- * @sst_drv_ctx                : driver context
- * @module             : FW module header
- * @memcpy_list        : Pointer to the list to be populated
- * Create the memcpy list as the number of block to be copied
- * returns error or 0 if module sizes are proper
- */
-static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx,
-               struct fw_module_header *module, struct list_head *memcpy_list)
-{
-       struct fw_block_info *block;
-       u32 count;
-       int ret_val = 0;
-       void __iomem *ram_iomem;
-
-       dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n",
-                       module->signature, module->mod_size,
-                       module->blocks, module->type);
-       dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point);
-
-       block = (void *)module + sizeof(*module);
-
-       for (count = 0; count < module->blocks; count++) {
-               if (block->size <= 0) {
-                       dev_err(sst_drv_ctx->dev, "block size invalid\n");
-                       return -EINVAL;
-               }
-               switch (block->type) {
-               case SST_IRAM:
-                       ram_iomem = sst_drv_ctx->iram;
-                       break;
-               case SST_DRAM:
-                       ram_iomem = sst_drv_ctx->dram;
-                       break;
-               case SST_DDR:
-                       ram_iomem = sst_drv_ctx->ddr;
-                       break;
-               case SST_CUSTOM_INFO:
-                       block = (void *)block + sizeof(*block) + block->size;
-                       continue;
-               default:
-                       dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n",
-                                       block->type, count);
-                       return -EINVAL;
-               }
-
-               ret_val = sst_fill_memcpy_list(memcpy_list,
-                               ram_iomem + block->ram_offset,
-                               (void *)block + sizeof(*block), block->size, 1);
-               if (ret_val)
-                       return ret_val;
-
-               block = (void *)block + sizeof(*block) + block->size;
-       }
-       return 0;
-}
-
-/**
- * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy
- *
- * @ctx                        : pointer to drv context
- * @size               : size of the firmware
- * @fw_list            : pointer to list_head to be populated
- * This function parses the FW image and saves the parsed image in the list
- * for memcpy
- */
-static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size,
-                               struct list_head *fw_list)
-{
-       struct fw_module_header *module;
-       u32 count, num_modules;
-       int ret_val;
-
-       ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules);
-       if (ret_val)
-               return ret_val;
-
-       for (count = 0; count < num_modules; count++) {
-               ret_val = sst_parse_module_memcpy(ctx, module, fw_list);
-               if (ret_val)
-                       return ret_val;
-               module = (void *)module + sizeof(*module) + module->mod_size;
-       }
-
-       return 0;
-}
-
-/**
- * sst_do_memcpy - function initiates the memcpy
- *
- * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated
- *
- * Triggers the memcpy
- */
-static void sst_do_memcpy(struct list_head *memcpy_list)
-{
-       struct sst_memcpy_list *listnode;
-
-       list_for_each_entry(listnode, memcpy_list, memcpylist) {
-               if (listnode->is_io == true)
-                       memcpy32_toio((void __iomem *)listnode->dstn,
-                                       listnode->src, listnode->size);
-               else
-                       memcpy(listnode->dstn, listnode->src, listnode->size);
-       }
-}
-
-void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx)
-{
-       struct sst_memcpy_list *listnode, *tmplistnode;
-
-       /* Free the list */
-       if (!list_empty(&sst_drv_ctx->memcpy_list)) {
-               list_for_each_entry_safe(listnode, tmplistnode,
-                               &sst_drv_ctx->memcpy_list, memcpylist) {
-                       list_del(&listnode->memcpylist);
-                       kfree(listnode);
-               }
-       }
-}
-
-static int sst_cache_and_parse_fw(struct intel_sst_drv *sst,
-               const struct firmware *fw)
-{
-       int retval = 0;
-
-       sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL);
-       if (!sst->fw_in_mem) {
-               retval = -ENOMEM;
-               goto end_release;
-       }
-       dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem);
-       dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem));
-       memcpy(sst->fw_in_mem, fw->data, fw->size);
-       retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list);
-       if (retval) {
-               dev_err(sst->dev, "Failed to parse fw\n");
-               kfree(sst->fw_in_mem);
-               sst->fw_in_mem = NULL;
-       }
-
-end_release:
-       release_firmware(fw);
-       return retval;
-
-}
-
-void sst_firmware_load_cb(const struct firmware *fw, void *context)
-{
-       struct intel_sst_drv *ctx = context;
-
-       dev_dbg(ctx->dev, "Enter\n");
-
-       if (fw == NULL) {
-               dev_err(ctx->dev, "request fw failed\n");
-               return;
-       }
-
-       mutex_lock(&ctx->sst_lock);
-
-       if (ctx->sst_state != SST_RESET ||
-                       ctx->fw_in_mem != NULL) {
-               release_firmware(fw);
-               mutex_unlock(&ctx->sst_lock);
-               return;
-       }
-
-       dev_dbg(ctx->dev, "Request Fw completed\n");
-       sst_cache_and_parse_fw(ctx, fw);
-       mutex_unlock(&ctx->sst_lock);
-}
-
-/*
- * sst_request_fw - requests audio fw from kernel and saves a copy
- *
- * This function requests the SST FW from the kernel, parses it and
- * saves a copy in the driver context
- */
-static int sst_request_fw(struct intel_sst_drv *sst)
-{
-       int retval = 0;
-       const struct firmware *fw;
-
-       retval = request_firmware(&fw, sst->firmware_name, sst->dev);
-       if (fw == NULL) {
-               dev_err(sst->dev, "fw is returning as null\n");
-               return -EINVAL;
-       }
-       if (retval) {
-               dev_err(sst->dev, "request fw failed %d\n", retval);
-               return retval;
-       }
-       mutex_lock(&sst->sst_lock);
-       retval = sst_cache_and_parse_fw(sst, fw);
-       mutex_unlock(&sst->sst_lock);
-
-       return retval;
-}
-
-/*
- * Writing the DDR physical base to DCCM offset
- * so that FW can use it to setup TLB
- */
-static void sst_dccm_config_write(void __iomem *dram_base,
-               unsigned int ddr_base)
-{
-       void __iomem *addr;
-       u32 bss_reset = 0;
-
-       addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET);
-       memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32));
-       bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT);
-       addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET);
-       memcpy32_toio(addr, &bss_reset, sizeof(u32));
-
-}
-
-void sst_post_download_mrfld(struct intel_sst_drv *ctx)
-{
-       sst_dccm_config_write(ctx->dram, ctx->ddr_base);
-       dev_dbg(ctx->dev, "config written to DCCM\n");
-}
-
-/**
- * sst_load_fw - function to load FW into DSP
- * Transfers the FW to DSP using dma/memcpy
- */
-int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
-{
-       int ret_val = 0;
-       struct sst_block *block;
-
-       dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n");
-
-       if (sst_drv_ctx->sst_state !=  SST_RESET ||
-                       sst_drv_ctx->sst_state == SST_SHUTDOWN)
-               return -EAGAIN;
-
-       if (!sst_drv_ctx->fw_in_mem) {
-               dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n");
-               ret_val = sst_request_fw(sst_drv_ctx);
-               if (ret_val)
-                       return ret_val;
-       }
-
-       BUG_ON(!sst_drv_ctx->fw_in_mem);
-       block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID);
-       if (block == NULL)
-               return -ENOMEM;
-
-       /* Prevent C-states beyond C6 */
-       pm_qos_update_request(sst_drv_ctx->qos, 0);
-
-       sst_drv_ctx->sst_state = SST_FW_LOADING;
-
-       ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx);
-       if (ret_val)
-               goto restore;
-
-       sst_do_memcpy(&sst_drv_ctx->memcpy_list);
-
-       /* Write the DRAM/DCCM config before enabling FW */
-       if (sst_drv_ctx->ops->post_download)
-               sst_drv_ctx->ops->post_download(sst_drv_ctx);
-
-       /* bring sst out of reset */
-       ret_val = sst_drv_ctx->ops->start(sst_drv_ctx);
-       if (ret_val)
-               goto restore;
-
-       ret_val = sst_wait_timeout(sst_drv_ctx, block);
-       if (ret_val) {
-               dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val);
-               /* FW download failed due to timeout */
-               ret_val = -EBUSY;
-
-       }
-
-
-restore:
-       /* Re-enable Deeper C-states beyond C6 */
-       pm_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE);
-       sst_free_block(sst_drv_ctx, block);
-       dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n");
-
-       if (sst_drv_ctx->ops->restore_dsp_context)
-               sst_drv_ctx->ops->restore_dsp_context();
-       sst_drv_ctx->sst_state = SST_FW_RUNNING;
-       return ret_val;
-}
-
diff --git a/sound/soc/intel/sst/sst_pci.c b/sound/soc/intel/sst/sst_pci.c
deleted file mode 100644 (file)
index 3a0b3bf..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- *  sst_pci.c - SST (LPE) driver init file for pci enumeration.
- *
- *  Copyright (C) 2008-14      Intel Corp
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com>
- *             KP Jeeja <jeeja.kp@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/firmware.h>
-#include <linux/pm_runtime.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <asm/platform_sst_audio.h>
-#include "../sst-mfld-platform.h"
-#include "sst.h"
-
-static int sst_platform_get_resources(struct intel_sst_drv *ctx)
-{
-       int ddr_base, ret = 0;
-       struct pci_dev *pci = ctx->pci;
-
-       ret = pci_request_regions(pci, SST_DRV_NAME);
-       if (ret)
-               return ret;
-
-       /* map registers */
-       /* DDR base */
-       if (ctx->dev_id == SST_MRFLD_PCI_ID) {
-               ctx->ddr_base = pci_resource_start(pci, 0);
-               /* check that the relocated IMR base matches with FW Binary */
-               ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base);
-               if (!ctx->pdata->lib_info) {
-                       dev_err(ctx->dev, "lib_info pointer NULL\n");
-                       ret = -EINVAL;
-                       goto do_release_regions;
-               }
-               if (ddr_base != ctx->pdata->lib_info->mod_base) {
-                       dev_err(ctx->dev,
-                                       "FW LSP DDR BASE does not match with IFWI\n");
-                       ret = -EINVAL;
-                       goto do_release_regions;
-               }
-               ctx->ddr_end = pci_resource_end(pci, 0);
-
-               ctx->ddr = pcim_iomap(pci, 0,
-                                       pci_resource_len(pci, 0));
-               if (!ctx->ddr) {
-                       ret = -EINVAL;
-                       goto do_release_regions;
-               }
-               dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr);
-       } else {
-               ctx->ddr = NULL;
-       }
-       /* SHIM */
-       ctx->shim_phy_add = pci_resource_start(pci, 1);
-       ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1));
-       if (!ctx->shim) {
-               ret = -EINVAL;
-               goto do_release_regions;
-       }
-       dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim);
-
-       /* Shared SRAM */
-       ctx->mailbox_add = pci_resource_start(pci, 2);
-       ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2));
-       if (!ctx->mailbox) {
-               ret = -EINVAL;
-               goto do_release_regions;
-       }
-       dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox);
-
-       /* IRAM */
-       ctx->iram_end = pci_resource_end(pci, 3);
-       ctx->iram_base = pci_resource_start(pci, 3);
-       ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3));
-       if (!ctx->iram) {
-               ret = -EINVAL;
-               goto do_release_regions;
-       }
-       dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram);
-
-       /* DRAM */
-       ctx->dram_end = pci_resource_end(pci, 4);
-       ctx->dram_base = pci_resource_start(pci, 4);
-       ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4));
-       if (!ctx->dram) {
-               ret = -EINVAL;
-               goto do_release_regions;
-       }
-       dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram);
-do_release_regions:
-       pci_release_regions(pci);
-       return 0;
-}
-
-/*
- * intel_sst_probe - PCI probe function
- *
- * @pci:       PCI device structure
- * @pci_id: PCI device ID structure
- *
- */
-static int intel_sst_probe(struct pci_dev *pci,
-                       const struct pci_device_id *pci_id)
-{
-       int ret = 0;
-       struct intel_sst_drv *sst_drv_ctx;
-       struct sst_platform_info *sst_pdata = pci->dev.platform_data;
-
-       dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device);
-       ret = sst_alloc_drv_context(&sst_drv_ctx, &pci->dev, pci->device);
-       if (ret < 0)
-               return ret;
-
-       sst_drv_ctx->pdata = sst_pdata;
-       sst_drv_ctx->irq_num = pci->irq;
-       snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name),
-                       "%s%04x%s", "fw_sst_",
-                       sst_drv_ctx->dev_id, ".bin");
-
-       ret = sst_context_init(sst_drv_ctx);
-       if (ret < 0)
-               return ret;
-
-       /* Init the device */
-       ret = pcim_enable_device(pci);
-       if (ret) {
-               dev_err(sst_drv_ctx->dev,
-                       "device can't be enabled. Returned err: %d\n", ret);
-               goto do_free_drv_ctx;
-       }
-       sst_drv_ctx->pci = pci_dev_get(pci);
-       ret = sst_platform_get_resources(sst_drv_ctx);
-       if (ret < 0)
-               goto do_free_drv_ctx;
-
-       pci_set_drvdata(pci, sst_drv_ctx);
-       sst_configure_runtime_pm(sst_drv_ctx);
-
-       return ret;
-
-do_free_drv_ctx:
-       sst_context_cleanup(sst_drv_ctx);
-       dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
-       return ret;
-}
-
-/**
- * intel_sst_remove - PCI remove function
- *
- * @pci:       PCI device structure
- *
- * This function is called by OS when a device is unloaded
- * This frees the interrupt etc
- */
-static void intel_sst_remove(struct pci_dev *pci)
-{
-       struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci);
-
-       sst_context_cleanup(sst_drv_ctx);
-       pci_dev_put(sst_drv_ctx->pci);
-       pci_release_regions(pci);
-       pci_set_drvdata(pci, NULL);
-}
-
-/* PCI Routines */
-static struct pci_device_id intel_sst_ids[] = {
-       { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
-       { 0, }
-};
-
-static struct pci_driver sst_driver = {
-       .name = SST_DRV_NAME,
-       .id_table = intel_sst_ids,
-       .probe = intel_sst_probe,
-       .remove = intel_sst_remove,
-#ifdef CONFIG_PM
-       .driver = {
-               .pm = &intel_sst_pm,
-       },
-#endif
-};
-
-module_pci_driver(sst_driver);
-
-MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver");
-MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
-MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
-MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
-MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("sst");
diff --git a/sound/soc/intel/sst/sst_pvt.c b/sound/soc/intel/sst/sst_pvt.c
deleted file mode 100644 (file)
index 4b77208..0000000
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- *  sst_pvt.c - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-14      Intel Corp
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com>
- *             KP Jeeja <jeeja.kp@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/kobject.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/firmware.h>
-#include <linux/pm_runtime.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <sound/asound.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include <asm/platform_sst_audio.h>
-#include "../sst-mfld-platform.h"
-#include "sst.h"
-#include "../sst-dsp.h"
-
-int sst_shim_write(void __iomem *addr, int offset, int value)
-{
-       writel(value, addr + offset);
-       return 0;
-}
-
-u32 sst_shim_read(void __iomem *addr, int offset)
-{
-       return readl(addr + offset);
-}
-
-u64 sst_reg_read64(void __iomem *addr, int offset)
-{
-       u64 val = 0;
-
-       memcpy_fromio(&val, addr + offset, sizeof(val));
-
-       return val;
-}
-
-int sst_shim_write64(void __iomem *addr, int offset, u64 value)
-{
-       memcpy_toio(addr + offset, &value, sizeof(value));
-       return 0;
-}
-
-u64 sst_shim_read64(void __iomem *addr, int offset)
-{
-       u64 val = 0;
-
-       memcpy_fromio(&val, addr + offset, sizeof(val));
-       return val;
-}
-
-void sst_set_fw_state_locked(
-               struct intel_sst_drv *sst_drv_ctx, int sst_state)
-{
-       mutex_lock(&sst_drv_ctx->sst_lock);
-       sst_drv_ctx->sst_state = sst_state;
-       mutex_unlock(&sst_drv_ctx->sst_lock);
-}
-
-/*
- * sst_wait_interruptible - wait on event
- *
- * @sst_drv_ctx: Driver context
- * @block: Driver block to wait on
- *
- * This function waits without a timeout (and is interruptable) for a
- * given block event
- */
-int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
-                               struct sst_block *block)
-{
-       int retval = 0;
-
-       if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
-                               block->condition)) {
-               /* event wake */
-               if (block->ret_code < 0) {
-                       dev_err(sst_drv_ctx->dev,
-                               "stream failed %d\n", block->ret_code);
-                       retval = -EBUSY;
-               } else {
-                       dev_dbg(sst_drv_ctx->dev, "event up\n");
-                       retval = 0;
-               }
-       } else {
-               dev_err(sst_drv_ctx->dev, "signal interrupted\n");
-               retval = -EINTR;
-       }
-       return retval;
-
-}
-
-unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr)
-{
-       unsigned long long val = 0;
-
-       switch (sst->dev_id) {
-       case SST_MRFLD_PCI_ID:
-       case SST_BYT_ACPI_ID:
-               val = sst_shim_read64(sst->shim, addr);
-               break;
-       }
-       return val;
-}
-
-void write_shim_data(struct intel_sst_drv *sst, int addr,
-                               unsigned long long data)
-{
-       switch (sst->dev_id) {
-       case SST_MRFLD_PCI_ID:
-       case SST_BYT_ACPI_ID:
-               sst_shim_write64(sst->shim, addr, (u64) data);
-               break;
-       }
-}
-
-/*
- * sst_wait_timeout - wait on event for timeout
- *
- * @sst_drv_ctx: Driver context
- * @block: Driver block to wait on
- *
- * This function waits with a timeout value (and is not interruptible) on a
- * given block event
- */
-int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, struct sst_block *block)
-{
-       int retval = 0;
-
-       /*
-        * NOTE:
-        * Observed that FW processes the alloc msg and replies even
-        * before the alloc thread has finished execution
-        */
-       dev_dbg(sst_drv_ctx->dev,
-               "waiting for condition %x ipc %d drv_id %d\n",
-               block->condition, block->msg_id, block->drv_id);
-       if (wait_event_timeout(sst_drv_ctx->wait_queue,
-                               block->condition,
-                               msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
-               /* event wake */
-               dev_dbg(sst_drv_ctx->dev, "Event wake %x\n",
-                               block->condition);
-               dev_dbg(sst_drv_ctx->dev, "message ret: %d\n",
-                               block->ret_code);
-               retval = -block->ret_code;
-       } else {
-               block->on = false;
-               dev_err(sst_drv_ctx->dev,
-                       "Wait timed-out condition:%#x, msg_id:%#x fw_state %#x\n",
-                       block->condition, block->msg_id, sst_drv_ctx->sst_state);
-               sst_drv_ctx->sst_state = SST_RESET;
-
-               retval = -EBUSY;
-       }
-       return retval;
-}
-
-/*
- * sst_create_ipc_msg - create a IPC message
- *
- * @arg: ipc message
- * @large: large or short message
- *
- * this function allocates structures to send a large or short
- * message to the firmware
- */
-int sst_create_ipc_msg(struct ipc_post **arg, bool large)
-{
-       struct ipc_post *msg;
-
-       msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
-       if (!msg)
-               return -ENOMEM;
-       if (large) {
-               msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
-               if (!msg->mailbox_data) {
-                       kfree(msg);
-                       return -ENOMEM;
-               }
-       } else {
-               msg->mailbox_data = NULL;
-       }
-       msg->is_large = large;
-       *arg = msg;
-       return 0;
-}
-
-/*
- * sst_create_block_and_ipc_msg - Creates IPC message and sst block
- * @arg: passed to sst_create_ipc_message API
- * @large: large or short message
- * @sst_drv_ctx: sst driver context
- * @block: return block allocated
- * @msg_id: IPC
- * @drv_id: stream id or private id
- */
-int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large,
-               struct intel_sst_drv *sst_drv_ctx, struct sst_block **block,
-               u32 msg_id, u32 drv_id)
-{
-       int retval = 0;
-
-       retval = sst_create_ipc_msg(arg, large);
-       if (retval)
-               return retval;
-       *block = sst_create_block(sst_drv_ctx, msg_id, drv_id);
-       if (*block == NULL) {
-               kfree(*arg);
-               return -ENOMEM;
-       }
-       return retval;
-}
-
-/*
- * sst_clean_stream - clean the stream context
- *
- * @stream: stream structure
- *
- * this function resets the stream contexts
- * should be called in free
- */
-void sst_clean_stream(struct stream_info *stream)
-{
-       stream->status = STREAM_UN_INIT;
-       stream->prev = STREAM_UN_INIT;
-       mutex_lock(&stream->lock);
-       stream->cumm_bytes = 0;
-       mutex_unlock(&stream->lock);
-}
-
-int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
-               int task_id, int ipc_msg, int cmd_id, int pipe_id,
-               size_t mbox_data_len, const void *mbox_data, void **data,
-               bool large, bool fill_dsp, bool sync, bool response)
-{
-       struct ipc_post *msg = NULL;
-       struct ipc_dsp_hdr dsp_hdr;
-       struct sst_block *block;
-       int ret = 0, pvt_id;
-
-       pvt_id = sst_assign_pvt_id(sst);
-       if (pvt_id < 0)
-               return pvt_id;
-
-       if (response)
-               ret = sst_create_block_and_ipc_msg(
-                               &msg, large, sst, &block, ipc_msg, pvt_id);
-       else
-               ret = sst_create_ipc_msg(&msg, large);
-
-       if (ret < 0) {
-               test_and_clear_bit(pvt_id, &sst->pvt_id);
-               return -ENOMEM;
-       }
-
-       dev_dbg(sst->dev, "pvt_id = %d, pipe id = %d, task = %d ipc_msg: %d\n",
-                pvt_id, pipe_id, task_id, ipc_msg);
-       sst_fill_header_mrfld(&msg->mrfld_header, ipc_msg,
-                                       task_id, large, pvt_id);
-       msg->mrfld_header.p.header_low_payload = sizeof(dsp_hdr) + mbox_data_len;
-       msg->mrfld_header.p.header_high.part.res_rqd = !sync;
-       dev_dbg(sst->dev, "header:%x\n",
-                       msg->mrfld_header.p.header_high.full);
-       dev_dbg(sst->dev, "response rqd: %x",
-                       msg->mrfld_header.p.header_high.part.res_rqd);
-       dev_dbg(sst->dev, "msg->mrfld_header.p.header_low_payload:%d",
-                       msg->mrfld_header.p.header_low_payload);
-       if (fill_dsp) {
-               sst_fill_header_dsp(&dsp_hdr, cmd_id, pipe_id, mbox_data_len);
-               memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr));
-               if (mbox_data_len) {
-                       memcpy(msg->mailbox_data + sizeof(dsp_hdr),
-                                       mbox_data, mbox_data_len);
-               }
-       }
-
-       if (sync)
-               sst->ops->post_message(sst, msg, true);
-       else
-               sst_add_to_dispatch_list_and_post(sst, msg);
-
-       if (response) {
-               ret = sst_wait_timeout(sst, block);
-               if (ret < 0) {
-                       goto out;
-               } else if(block->data) {
-                       if (!data)
-                               goto out;
-                       *data = kzalloc(block->size, GFP_KERNEL);
-                       if (!(*data)) {
-                               ret = -ENOMEM;
-                               goto out;
-                       } else
-                               memcpy(data, (void *) block->data, block->size);
-               }
-       }
-out:
-       if (response)
-               sst_free_block(sst, block);
-       test_and_clear_bit(pvt_id, &sst->pvt_id);
-       return ret;
-}
-
-int sst_pm_runtime_put(struct intel_sst_drv *sst_drv)
-{
-       int ret;
-
-       pm_runtime_mark_last_busy(sst_drv->dev);
-       ret = pm_runtime_put_autosuspend(sst_drv->dev);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-void sst_fill_header_mrfld(union ipc_header_mrfld *header,
-                               int msg, int task_id, int large, int drv_id)
-{
-       header->full = 0;
-       header->p.header_high.part.msg_id = msg;
-       header->p.header_high.part.task_id = task_id;
-       header->p.header_high.part.large = large;
-       header->p.header_high.part.drv_id = drv_id;
-       header->p.header_high.part.done = 0;
-       header->p.header_high.part.busy = 1;
-       header->p.header_high.part.res_rqd = 1;
-}
-
-void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg,
-                                       int pipe_id, int len)
-{
-       dsp->cmd_id = msg;
-       dsp->mod_index_id = 0xff;
-       dsp->pipe_id = pipe_id;
-       dsp->length = len;
-       dsp->mod_id = 0;
-}
-
-#define SST_MAX_BLOCKS 15
-/*
- * sst_assign_pvt_id - assign a pvt id for stream
- *
- * @sst_drv_ctx : driver context
- *
- * this function assigns a private id for calls that dont have stream
- * context yet, should be called with lock held
- * uses bits for the id, and finds first free bits and assigns that
- */
-int sst_assign_pvt_id(struct intel_sst_drv *drv)
-{
-       int local;
-
-       spin_lock(&drv->block_lock);
-       /* find first zero index from lsb */
-       local = ffz(drv->pvt_id);
-       dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local);
-       if (local >= SST_MAX_BLOCKS){
-               spin_unlock(&drv->block_lock);
-               dev_err(drv->dev, "PVT _ID error: no free id blocks ");
-               return -EINVAL;
-       }
-       /* toggle the index */
-       change_bit(local, &drv->pvt_id);
-       spin_unlock(&drv->block_lock);
-       return local;
-}
-
-void sst_init_stream(struct stream_info *stream,
-               int codec, int sst_id, int ops, u8 slot)
-{
-       stream->status = STREAM_INIT;
-       stream->prev = STREAM_UN_INIT;
-       stream->ops = ops;
-}
-
-int sst_validate_strid(
-               struct intel_sst_drv *sst_drv_ctx, int str_id)
-{
-       if (str_id <= 0 || str_id > sst_drv_ctx->info.max_streams) {
-               dev_err(sst_drv_ctx->dev,
-                       "SST ERR: invalid stream id : %d, max %d\n",
-                       str_id, sst_drv_ctx->info.max_streams);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-struct stream_info *get_stream_info(
-               struct intel_sst_drv *sst_drv_ctx, int str_id)
-{
-       if (sst_validate_strid(sst_drv_ctx, str_id))
-               return NULL;
-       return &sst_drv_ctx->streams[str_id];
-}
-
-int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx,
-               u32 pipe_id)
-{
-       int i;
-
-       for (i = 1; i <= sst_drv_ctx->info.max_streams; i++)
-               if (pipe_id == sst_drv_ctx->streams[i].pipe_id)
-                       return i;
-
-       dev_dbg(sst_drv_ctx->dev, "no such pipe_id(%u)", pipe_id);
-       return -1;
-}
-
-u32 relocate_imr_addr_mrfld(u32 base_addr)
-{
-       /* Get the difference from 512MB aligned base addr */
-       /* relocate the base */
-       base_addr = MRFLD_FW_VIRTUAL_BASE + (base_addr % (512 * 1024 * 1024));
-       return base_addr;
-}
-EXPORT_SYMBOL_GPL(relocate_imr_addr_mrfld);
-
-void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst,
-                                               struct ipc_post *msg)
-{
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&sst->ipc_spin_lock, irq_flags);
-       list_add_tail(&msg->node, &sst->ipc_dispatch_list);
-       spin_unlock_irqrestore(&sst->ipc_spin_lock, irq_flags);
-       sst->ops->post_message(sst, NULL, false);
-}
diff --git a/sound/soc/intel/sst/sst_stream.c b/sound/soc/intel/sst/sst_stream.c
deleted file mode 100644 (file)
index dae2a41..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- *  sst_stream.c - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-14 Intel Corp
- *  Authors:   Vinod Koul <vinod.koul@intel.com>
- *             Harsha Priya <priya.harsha@intel.com>
- *             Dharageswari R <dharageswari.r@intel.com>
- *             KP Jeeja <jeeja.kp@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/pci.h>
-#include <linux/firmware.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include <asm/platform_sst_audio.h>
-#include "../sst-mfld-platform.h"
-#include "sst.h"
-#include "../sst-dsp.h"
-
-int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
-{
-       struct snd_sst_alloc_mrfld alloc_param;
-       struct snd_sst_params *str_params;
-       struct snd_sst_tstamp fw_tstamp;
-       struct stream_info *str_info;
-       struct snd_sst_alloc_response *response;
-       unsigned int str_id, pipe_id, task_id;
-       int i, num_ch, ret = 0;
-       void *data = NULL;
-
-       dev_dbg(sst_drv_ctx->dev, "Enter\n");
-       BUG_ON(!params);
-
-       str_params = (struct snd_sst_params *)params;
-       memset(&alloc_param, 0, sizeof(alloc_param));
-       alloc_param.operation = str_params->ops;
-       alloc_param.codec_type = str_params->codec;
-       alloc_param.sg_count = str_params->aparams.sg_count;
-       alloc_param.ring_buf_info[0].addr =
-               str_params->aparams.ring_buf_info[0].addr;
-       alloc_param.ring_buf_info[0].size =
-               str_params->aparams.ring_buf_info[0].size;
-       alloc_param.frag_size = str_params->aparams.frag_size;
-
-       memcpy(&alloc_param.codec_params, &str_params->sparams,
-                       sizeof(struct snd_sst_stream_params));
-
-       /*
-        * fill channel map params for multichannel support.
-        * Ideally channel map should be received from upper layers
-        * for multichannel support.
-        * Currently hardcoding as per FW reqm.
-        */
-       num_ch = sst_get_num_channel(str_params);
-       for (i = 0; i < 8; i++) {
-               if (i < num_ch)
-                       alloc_param.codec_params.uc.pcm_params.channel_map[i] = i;
-               else
-                       alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF;
-       }
-
-       str_id = str_params->stream_id;
-       str_info = get_stream_info(sst_drv_ctx, str_id);
-       if (str_info == NULL) {
-               dev_err(sst_drv_ctx->dev, "get stream info returned null\n");
-               return -EINVAL;
-       }
-
-       pipe_id = str_params->device_type;
-       task_id = str_params->task;
-       sst_drv_ctx->streams[str_id].pipe_id = pipe_id;
-       sst_drv_ctx->streams[str_id].task_id = task_id;
-       sst_drv_ctx->streams[str_id].num_ch = num_ch;
-
-       if (sst_drv_ctx->info.lpe_viewpt_rqd)
-               alloc_param.ts = sst_drv_ctx->info.mailbox_start +
-                       sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
-       else
-               alloc_param.ts = sst_drv_ctx->mailbox_add +
-                       sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
-
-       dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n",
-                       alloc_param.ts);
-       dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
-                       pipe_id, task_id);
-
-       /* allocate device type context */
-       sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type,
-                       str_id, alloc_param.operation, 0);
-
-       dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
-                       str_id, pipe_id);
-       ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,
-                       IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param),
-                       &alloc_param, data, true, true, false, true);
-
-       if (ret < 0) {
-               dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
-               /* alloc failed, so reset the state to uninit */
-               str_info->status = STREAM_UN_INIT;
-               str_id = ret;
-       } else if (data) {
-               response = (struct snd_sst_alloc_response *)data;
-               ret = response->str_type.result;
-               if (!ret)
-                       goto out;
-               dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
-               if (ret == SST_ERR_STREAM_IN_USE) {
-                       dev_err(sst_drv_ctx->dev,
-                               "FW not in clean state, send free for:%d\n", str_id);
-                       sst_free_stream(sst_drv_ctx, str_id);
-               }
-               str_id = -ret;
-       }
-out:
-       kfree(data);
-       return str_id;
-}
-
-/**
-* sst_start_stream - Send msg for a starting stream
-* @str_id:      stream ID
-*
-* This function is called by any function which wants to start
-* a stream.
-*/
-int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
-{
-       int retval = 0;
-       struct stream_info *str_info;
-       u16 data = 0;
-
-       dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id);
-       str_info = get_stream_info(sst_drv_ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-       if (str_info->status != STREAM_RUNNING)
-               return -EBADRQC;
-
-       retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
-                       IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id,
-                       sizeof(u16), &data, NULL, true, true, true, false);
-
-       return retval;
-}
-
-int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
-               struct snd_sst_bytes_v2 *bytes)
-{      struct ipc_post *msg = NULL;
-       u32 length;
-       int pvt_id, ret = 0;
-       struct sst_block *block = NULL;
-
-       dev_dbg(sst_drv_ctx->dev,
-               "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
-               bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
-               bytes->pipe_id, bytes->len);
-
-       if (sst_create_ipc_msg(&msg, true))
-               return -ENOMEM;
-
-       pvt_id = sst_assign_pvt_id(sst_drv_ctx);
-       sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
-                       bytes->task_id, 1, pvt_id);
-       msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
-       length = bytes->len;
-       msg->mrfld_header.p.header_low_payload = length;
-       dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
-       memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
-       if (bytes->block) {
-               block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
-               if (block == NULL) {
-                       kfree(msg);
-                       ret = -ENOMEM;
-                       goto out;
-               }
-       }
-
-       sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg);
-       dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
-                       msg->mrfld_header.p.header_low_payload);
-
-       if (bytes->block) {
-               ret = sst_wait_timeout(sst_drv_ctx, block);
-               if (ret) {
-                       dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
-                       sst_free_block(sst_drv_ctx, block);
-                       goto out;
-               }
-       }
-       if (bytes->type == SND_SST_BYTES_GET) {
-               /*
-                * copy the reply and send back
-                * we need to update only sz and payload
-                */
-               if (bytes->block) {
-                       unsigned char *r = block->data;
-
-                       dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
-                                       bytes->len);
-                       memcpy(bytes->bytes, r, bytes->len);
-               }
-       }
-       if (bytes->block)
-               sst_free_block(sst_drv_ctx, block);
-out:
-       test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
-       return 0;
-}
-
-/*
- * sst_pause_stream - Send msg for a pausing stream
- * @str_id:     stream ID
- *
- * This function is called by any function which wants to pause
- * an already running stream.
- */
-int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
-{
-       int retval = 0;
-       struct stream_info *str_info;
-
-       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id);
-       str_info = get_stream_info(sst_drv_ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-       if (str_info->status == STREAM_PAUSED)
-               return 0;
-       if (str_info->status == STREAM_RUNNING ||
-               str_info->status == STREAM_INIT) {
-               if (str_info->prev == STREAM_UN_INIT)
-                       return -EBADRQC;
-
-               retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
-                               IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
-                               0, NULL, NULL, true, true, false, true);
-
-               if (retval == 0) {
-                       str_info->prev = str_info->status;
-                       str_info->status = STREAM_PAUSED;
-               } else if (retval == SST_ERR_INVALID_STREAM_ID) {
-                       retval = -EINVAL;
-                       mutex_lock(&sst_drv_ctx->sst_lock);
-                       sst_clean_stream(str_info);
-                       mutex_unlock(&sst_drv_ctx->sst_lock);
-               }
-       } else {
-               retval = -EBADRQC;
-               dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n ");
-       }
-
-       return retval;
-}
-
-/**
- * sst_resume_stream - Send msg for resuming stream
- * @str_id:            stream ID
- *
- * This function is called by any function which wants to resume
- * an already paused stream.
- */
-int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
-{
-       int retval = 0;
-       struct stream_info *str_info;
-
-       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id);
-       str_info = get_stream_info(sst_drv_ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-       if (str_info->status == STREAM_RUNNING)
-                       return 0;
-       if (str_info->status == STREAM_PAUSED) {
-               retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
-                               IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
-                               str_info->pipe_id, 0, NULL, NULL,
-                               true, true, false, true);
-
-               if (!retval) {
-                       if (str_info->prev == STREAM_RUNNING)
-                               str_info->status = STREAM_RUNNING;
-                       else
-                               str_info->status = STREAM_INIT;
-                       str_info->prev = STREAM_PAUSED;
-               } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
-                       retval = -EINVAL;
-                       mutex_lock(&sst_drv_ctx->sst_lock);
-                       sst_clean_stream(str_info);
-                       mutex_unlock(&sst_drv_ctx->sst_lock);
-               }
-       } else {
-               retval = -EBADRQC;
-               dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n");
-       }
-
-       return retval;
-}
-
-
-/**
- * sst_drop_stream - Send msg for stopping stream
- * @str_id:            stream ID
- *
- * This function is called by any function which wants to stop
- * a stream.
- */
-int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
-{
-       int retval = 0;
-       struct stream_info *str_info;
-
-       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id);
-       str_info = get_stream_info(sst_drv_ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-
-       if (str_info->status != STREAM_UN_INIT) {
-               str_info->prev = STREAM_UN_INIT;
-               str_info->status = STREAM_INIT;
-               str_info->cumm_bytes = 0;
-               retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
-                               IPC_CMD, IPC_IA_DROP_STREAM_MRFLD,
-                               str_info->pipe_id, 0, NULL, NULL,
-                               true, true, true, false);
-       } else {
-               retval = -EBADRQC;
-               dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
-                               str_info->status);
-       }
-       return retval;
-}
-
-/**
-* sst_drain_stream - Send msg for draining stream
-* @str_id:             stream ID
-*
-* This function is called by any function which wants to drain
-* a stream.
-*/
-int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
-                       int str_id, bool partial_drain)
-{
-       int retval = 0;
-       struct stream_info *str_info;
-
-       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id);
-       str_info = get_stream_info(sst_drv_ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-       if (str_info->status != STREAM_RUNNING &&
-               str_info->status != STREAM_INIT &&
-               str_info->status != STREAM_PAUSED) {
-                       dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n",
-                                      str_info->status);
-                       return -EBADRQC;
-       }
-
-       retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
-                       IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id,
-                       sizeof(u8), &partial_drain, NULL, true, true, false, false);
-       /*
-        * with new non blocked drain implementation in core we dont need to
-        * wait for respsonse, and need to only invoke callback for drain
-        * complete
-        */
-
-       return retval;
-}
-
-/**
- * sst_free_stream - Frees a stream
- * @str_id:            stream ID
- *
- * This function is called by any function which wants to free
- * a stream.
- */
-int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
-{
-       int retval = 0;
-       struct stream_info *str_info;
-       struct intel_sst_ops *ops;
-
-       dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
-
-       mutex_lock(&sst_drv_ctx->sst_lock);
-       if (sst_drv_ctx->sst_state == SST_RESET) {
-               mutex_unlock(&sst_drv_ctx->sst_lock);
-               return -ENODEV;
-       }
-       mutex_unlock(&sst_drv_ctx->sst_lock);
-       str_info = get_stream_info(sst_drv_ctx, str_id);
-       if (!str_info)
-               return -EINVAL;
-       ops = sst_drv_ctx->ops;
-
-       mutex_lock(&str_info->lock);
-       if (str_info->status != STREAM_UN_INIT) {
-               str_info->prev =  str_info->status;
-               str_info->status = STREAM_UN_INIT;
-               mutex_unlock(&str_info->lock);
-
-               dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
-                               str_id, str_info->pipe_id);
-               retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
-                               IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
-                               NULL, NULL, true, true, false, true);
-
-               dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n",
-                               retval);
-               mutex_lock(&sst_drv_ctx->sst_lock);
-               sst_clean_stream(str_info);
-               mutex_unlock(&sst_drv_ctx->sst_lock);
-               dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n");
-       } else {
-               mutex_unlock(&str_info->lock);
-               retval = -EBADRQC;
-               dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n");
-       }
-
-       return retval;
-}
index def7d82..d194830 100644 (file)
@@ -579,7 +579,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
                if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
        } else {
-               if (priv->extclk == priv->clk) {
+               if (clk_is_match(priv->extclk, priv->clk)) {
                        devm_clk_put(&pdev->dev, priv->extclk);
                        priv->extclk = ERR_PTR(-EINVAL);
                } else {
index a2cd348..e7c78b0 100644 (file)
@@ -100,17 +100,19 @@ config SND_OMAP_SOC_OMAP_TWL4030
 
 config SND_OMAP_SOC_OMAP_ABE_TWL6040
        tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
-       depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST)
+       depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST)
        select SND_OMAP_SOC_DMIC
        select SND_OMAP_SOC_MCPDM
        select SND_SOC_TWL6040
        select SND_SOC_DMIC
+       select COMMON_CLK_PALMAS if SOC_OMAP5
        help
          Say Y if you want to add support for SoC audio on OMAP boards using
          ABE and twl6040 codec. This driver currently supports:
          - SDP4430/Blaze boards
          - PandaBoard (4430)
          - PandaBoardES (4460)
+         - omap5-uevm (5432)
 
 config SND_OMAP_SOC_OMAP3_PANDORA
        tristate "SoC Audio support for OMAP3 Pandora"
index 7066130..16cc95f 100644 (file)
@@ -479,8 +479,8 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
 
        /* Add hook switch - can be used to control the codec from userspace
         * even if line discipline fails */
-       ret = snd_soc_jack_new(rtd->codec, "hook_switch",
-                               SND_JACK_HEADSET, &ams_delta_hook_switch);
+       ret = snd_soc_card_jack_new(card, "hook_switch", SND_JACK_HEADSET,
+                                   &ams_delta_hook_switch, NULL, 0);
        if (ret)
                dev_warn(card->dev,
                                "Failed to allocate resources for hook switch, "
index b9c65f1..0843a68 100644 (file)
@@ -182,17 +182,17 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 
        /* Headset jack detection only if it is supported */
        if (priv->jack_detection) {
-               ret = snd_soc_jack_new(codec, "Headset Jack",
-                                       SND_JACK_HEADSET, &hs_jack);
+               ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                           SND_JACK_HEADSET, &hs_jack,
+                                           hs_jack_pins,
+                                           ARRAY_SIZE(hs_jack_pins));
                if (ret)
                        return ret;
 
-               ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                                       hs_jack_pins);
                twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
        }
 
-       return ret;
+       return 0;
 }
 
 static const struct snd_soc_dapm_route dmic_audio_map[] = {
index ccfb41c..f7eb42a 100644 (file)
@@ -352,6 +352,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
                return ret;
 
        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
        card->name = devm_kasprintf(dev, GFP_KERNEL,
                                    "HDMI %s", dev_name(ad->dssdev));
        card->owner = THIS_MODULE;
index c7eb9dd..fd99d89 100644 (file)
@@ -530,8 +530,19 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 
        case OMAP_MCBSP_SYSCLK_CLKX_EXT:
                regs->srgr2     |= CLKSM;
+               regs->pcr0      |= SCLKME;
+               /*
+                * If McBSP is master but yet the CLKX/CLKR pin drives the SRG,
+                * disable output on those pins. This enables to inject the
+                * reference clock through CLKX/CLKR. For this to work
+                * set_dai_sysclk() _needs_ to be called after set_dai_fmt().
+                */
+               regs->pcr0      &= ~CLKXM;
+               break;
        case OMAP_MCBSP_SYSCLK_CLKR_EXT:
                regs->pcr0      |= SCLKME;
+               /* Disable ouput on CLKR pin in master mode */
+               regs->pcr0      &= ~CLKRM;
                break;
        default:
                err = -ENODEV;
index f4b05bc..6bb623a 100644 (file)
@@ -39,7 +39,7 @@
 #define pcm_omap1510() 0
 #endif
 
-static const struct snd_pcm_hardware omap_pcm_hardware = {
+static struct snd_pcm_hardware omap_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
                                  SNDRV_PCM_INFO_INTERLEAVED |
@@ -53,6 +53,24 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
        .buffer_bytes_max       = 128 * 1024,
 };
 
+/* sDMA supports only 1, 2, and 4 byte transfer elements. */
+static void omap_pcm_limit_supported_formats(void)
+{
+       int i;
+
+       for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
+               switch (snd_pcm_format_physical_width(i)) {
+               case 8:
+               case 16:
+               case 32:
+                       omap_pcm_hardware.formats |= (1LL << i);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
 /* this may get called several times by oss emulation */
 static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *params)
@@ -201,7 +219,7 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
        struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
-       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(64));
+       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
        if (ret)
                return ret;
 
@@ -235,6 +253,7 @@ static struct snd_soc_platform_driver omap_soc_platform = {
 
 int omap_pcm_platform_register(struct device *dev)
 {
+       omap_pcm_limit_supported_formats();
        return devm_snd_soc_register_platform(dev, &omap_soc_platform);
 }
 EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
index fb1f6bb..3673ada 100644 (file)
@@ -170,14 +170,10 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
        if (priv->jack_detect > 0) {
                hs_jack_gpios[0].gpio = priv->jack_detect;
 
-               ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
-                                      &priv->hs_jack);
-               if (ret)
-                       return ret;
-
-               ret = snd_soc_jack_add_pins(&priv->hs_jack,
-                                           ARRAY_SIZE(hs_jack_pins),
-                                           hs_jack_pins);
+               ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                           SND_JACK_HEADSET, &priv->hs_jack,
+                                           hs_jack_pins,
+                                           ARRAY_SIZE(hs_jack_pins));
                if (ret)
                        return ret;
 
index 7f29935..c2ddf0f 100644 (file)
@@ -311,9 +311,9 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        /* AV jack detection */
-       err = snd_soc_jack_new(codec, "AV Jack",
-                              SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
-                              &rx51_av_jack);
+       err = snd_soc_card_jack_new(rtd->card, "AV Jack",
+                                   SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
+                                   &rx51_av_jack, NULL, 0);
        if (err) {
                dev_err(card->dev, "Failed to add AV Jack\n");
                return err;
index 73eb5dd..9f8be7c 100644 (file)
@@ -126,17 +126,12 @@ static const struct snd_soc_dapm_route hx4700_audio_map[] = {
  */
 static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* Jack detection API stuff */
-       err = snd_soc_jack_new(codec, "Headphone Jack",
-                               SND_JACK_HEADPHONE, &hs_jack);
-       if (err)
-               return err;
-
-       err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin),
-                                       hs_jack_pin);
+       err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+                                   SND_JACK_HEADPHONE, &hs_jack, hs_jack_pin,
+                                   ARRAY_SIZE(hs_jack_pin));
        if (err)
                return err;
 
index 910336c..c20bbc0 100644 (file)
@@ -75,17 +75,12 @@ static struct snd_soc_card palm27x_asoc;
 
 static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* Jack detection API stuff */
-       err = snd_soc_jack_new(codec, "Headphone Jack",
-                               SND_JACK_HEADPHONE, &hs_jack);
-       if (err)
-               return err;
-
-       err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                               hs_jack_pins);
+       err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+                                   SND_JACK_HEADPHONE, &hs_jack, hs_jack_pins,
+                                   ARRAY_SIZE(hs_jack_pins));
        if (err)
                return err;
 
index 5001dbb..1753c7d 100644 (file)
@@ -78,15 +78,12 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_codec *codec = rtd->codec;
 
        /* Headset jack detection */
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
-                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
-                       &hs_jack);
-       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                             hs_jack_pins);
-       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
-                        &mic_jack);
-       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
-                             mic_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE |
+                             SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+                             &hs_jack, hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
+       snd_soc_card_jack_new(rtd->card, "Microphone Jack", SND_JACK_MICROPHONE,
+                             &mic_jack, mic_jack_pins,
+                             ARRAY_SIZE(mic_jack_pins));
 
        /* headphone, microphone detection & headset short detection */
        pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
index 76ccb17..bcbfbe8 100644 (file)
@@ -143,13 +143,9 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_disable_pin(dapm, "MONO1");
 
        /* Jack detection API stuff */
-       ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
-                               &hs_jack);
-       if (ret)
-               goto err;
-
-       ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                               hs_jack_pins);
+       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
+                                   &hs_jack, hs_jack_pins,
+                                   ARRAY_SIZE(hs_jack_pins));
        if (ret)
                goto err;
 
index 3cebf6c..0632a36 100644 (file)
@@ -174,7 +174,7 @@ config SND_SOC_SMDK_WM8994_PCM
 
 config SND_SOC_SPEYSIDE
        tristate "Audio support for Wolfson Speyside"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C && SPI_MASTER
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8996
        select SND_SOC_WM9081
@@ -189,7 +189,7 @@ config SND_SOC_TOBERMORY
 
 config SND_SOC_BELLS
        tristate "Audio support for Wolfson Bells"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA && I2C && SPI_MASTER
        select SND_SAMSUNG_I2S
        select SND_SOC_WM5102
        select SND_SOC_WM5110
@@ -206,7 +206,7 @@ config SND_SOC_LOWLAND
 
 config SND_SOC_LITTLEMILL
        tristate "Audio support for Wolfson Littlemill"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C
        select SND_SAMSUNG_I2S
        select MFD_WM8994
        select SND_SOC_WM8994
@@ -223,7 +223,7 @@ config SND_SOC_SNOW
 
 config SND_SOC_ODROIDX2
        tristate "Audio support for Odroid-X2 and Odroid-U3"
-       depends on SND_SOC_SAMSUNG
+       depends on SND_SOC_SAMSUNG && I2C
        select SND_SOC_MAX98090
        select SND_SAMSUNG_I2S
        help
@@ -231,6 +231,6 @@ config SND_SOC_ODROIDX2
 
 config SND_SOC_ARNDALE_RT5631_ALC5631
         tristate "Audio support for RT5631(ALC5631) on Arndale Board"
-        depends on SND_SOC_SAMSUNG
+        depends on SND_SOC_SAMSUNG && I2C
         select SND_SAMSUNG_I2S
         select SND_SOC_RT5631
index 59b0442..c72e9fb 100644 (file)
@@ -162,13 +162,8 @@ static struct platform_device *s3c24xx_snd_device;
 
 static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-               &hp_jack);
-
-       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
-               hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
+               &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
 
        snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
                hp_jack_gpios);
index 141519c..31a820e 100644 (file)
@@ -260,12 +260,12 @@ static int littlemill_late_probe(struct snd_soc_card *card)
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_HEADSET | SND_JACK_MECHANICAL |
-                              SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                              SND_JACK_BTN_2 | SND_JACK_BTN_3 |
-                              SND_JACK_BTN_4 | SND_JACK_BTN_5,
-                              &littlemill_headset);
+       ret = snd_soc_card_jack_new(card, "Headset",
+                                   SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                   SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                                   SND_JACK_BTN_4 | SND_JACK_BTN_5,
+                                   &littlemill_headset, NULL, 0);
        if (ret)
                return ret;
 
index 243dea7..5f15609 100644 (file)
@@ -56,16 +56,10 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_LINEOUT | SND_JACK_HEADSET |
-                              SND_JACK_BTN_0,
-                              &lowland_headset);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&lowland_headset,
-                                   ARRAY_SIZE(lowland_headset_pins),
-                                   lowland_headset_pins);
+       ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT |
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                   &lowland_headset, lowland_headset_pins,
+                                   ARRAY_SIZE(lowland_headset_pins));
        if (ret)
                return ret;
 
index 873f2cb..35e37c4 100644 (file)
@@ -211,13 +211,8 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
 
 static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-               &hp_jack);
-
-       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
-               hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
+               &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
 
        snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
                hp_jack_gpios);
index 8291d2a..dfbe2db 100644 (file)
@@ -151,13 +151,10 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
 
        /* Headphone jack detection */
-       err = snd_soc_jack_new(codec, "Headphone Jack",
-                              SND_JACK_HEADPHONE, &smartq_jack);
-       if (err)
-               return err;
-
-       err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
-                                   smartq_jack_pins);
+       err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+                                   SND_JACK_HEADPHONE, &smartq_jack,
+                                   smartq_jack_pins,
+                                   ARRAY_SIZE(smartq_jack_pins));
        if (err)
                return err;
 
index 5ec7c52..2dcb988 100644 (file)
@@ -153,16 +153,10 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
                pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
        gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
 
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_LINEOUT | SND_JACK_HEADSET |
-                              SND_JACK_BTN_0,
-                              &speyside_headset);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&speyside_headset,
-                                   ARRAY_SIZE(speyside_headset_pins),
-                                   speyside_headset_pins);
+       ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT |
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                   &speyside_headset, speyside_headset_pins,
+                                   ARRAY_SIZE(speyside_headset_pins));
        if (ret)
                return ret;
 
index 9c80506..85ccfb7 100644 (file)
@@ -179,15 +179,10 @@ static int tobermory_late_probe(struct snd_soc_card *card)
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_HEADSET | SND_JACK_BTN_0,
-                              &tobermory_headset);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&tobermory_headset,
-                                   ARRAY_SIZE(tobermory_headset_pins),
-                                   tobermory_headset_pins);
+       ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET |
+                                   SND_JACK_BTN_0, &tobermory_headset,
+                                   tobermory_headset_pins,
+                                   ARRAY_SIZE(tobermory_headset_pins));
        if (ret)
                return ret;
 
index 1b53605..31202e9 100644 (file)
@@ -149,16 +149,29 @@ char *rsnd_mod_dma_name(struct rsnd_mod *mod)
        return mod->ops->dma_name(mod);
 }
 
-void rsnd_mod_init(struct rsnd_mod *mod,
+int rsnd_mod_init(struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
                   struct clk *clk,
                   enum rsnd_mod_type type,
                   int id)
 {
+       int ret = clk_prepare(clk);
+
+       if (ret)
+               return ret;
+
        mod->id         = id;
        mod->ops        = ops;
        mod->type       = type;
        mod->clk        = clk;
+
+       return ret;
+}
+
+void rsnd_mod_quit(struct rsnd_mod *mod)
+{
+       if (mod->clk)
+               clk_unprepare(mod->clk);
 }
 
 /*
@@ -1252,6 +1265,8 @@ static int rsnd_probe(struct platform_device *pdev)
                        goto exit_snd_probe;
        }
 
+       dev_set_drvdata(dev, priv);
+
        /*
         *      asoc register
         */
@@ -1268,8 +1283,6 @@ static int rsnd_probe(struct platform_device *pdev)
                goto exit_snd_soc;
        }
 
-       dev_set_drvdata(dev, priv);
-
        pm_runtime_enable(dev);
 
        dev_info(dev, "probed\n");
@@ -1290,6 +1303,12 @@ static int rsnd_remove(struct platform_device *pdev)
 {
        struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
        struct rsnd_dai *rdai;
+       void (*remove_func[])(struct platform_device *pdev,
+                             struct rsnd_priv *priv) = {
+               rsnd_ssi_remove,
+               rsnd_src_remove,
+               rsnd_dvc_remove,
+       };
        int ret = 0, i;
 
        pm_runtime_disable(&pdev->dev);
@@ -1299,6 +1318,9 @@ static int rsnd_remove(struct platform_device *pdev)
                ret |= rsnd_dai_call(remove, &rdai->capture, priv);
        }
 
+       for (i = 0; i < ARRAY_SIZE(remove_func); i++)
+               remove_func[i](pdev, priv);
+
        snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
 
index d7f9ed9..261997a 100644 (file)
@@ -333,7 +333,7 @@ int rsnd_dvc_probe(struct platform_device *pdev,
        struct rsnd_dvc *dvc;
        struct clk *clk;
        char name[RSND_DVC_NAME_SIZE];
-       int i, nr;
+       int i, nr, ret;
 
        rsnd_of_parse_dvc(pdev, of_data, priv);
 
@@ -366,11 +366,24 @@ int rsnd_dvc_probe(struct platform_device *pdev,
 
                dvc->info = &info->dvc_info[i];
 
-               rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops,
+               ret = rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops,
                              clk, RSND_MOD_DVC, i);
+               if (ret)
+                       return ret;
 
                dev_dbg(dev, "CMD%d probed\n", i);
        }
 
        return 0;
 }
+
+void rsnd_dvc_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_dvc *dvc;
+       int i;
+
+       for_each_rsnd_dvc(dvc, priv, i) {
+               rsnd_mod_quit(&dvc->mod);
+       }
+}
index e7914bd..1bccc55 100644 (file)
@@ -260,14 +260,15 @@ struct rsnd_mod {
 #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
 #define rsnd_mod_to_io(mod) ((mod)->io)
 #define rsnd_mod_id(mod) ((mod)->id)
-#define rsnd_mod_hw_start(mod) clk_prepare_enable((mod)->clk)
-#define rsnd_mod_hw_stop(mod)  clk_disable_unprepare((mod)->clk)
+#define rsnd_mod_hw_start(mod) clk_enable((mod)->clk)
+#define rsnd_mod_hw_stop(mod)  clk_disable((mod)->clk)
 
-void rsnd_mod_init(struct rsnd_mod *mod,
+int rsnd_mod_init(struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
                   struct clk *clk,
                   enum rsnd_mod_type type,
                   int id);
+void rsnd_mod_quit(struct rsnd_mod *mod);
 char *rsnd_mod_name(struct rsnd_mod *mod);
 char *rsnd_mod_dma_name(struct rsnd_mod *mod);
 
@@ -480,6 +481,8 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
 int rsnd_src_probe(struct platform_device *pdev,
                   const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
+void rsnd_src_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
 unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
                                   struct rsnd_dai_stream *io,
@@ -498,6 +501,8 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
 int rsnd_ssi_probe(struct platform_device *pdev,
                   const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
index 81c182b..c77d059 100644 (file)
@@ -850,7 +850,7 @@ int rsnd_src_probe(struct platform_device *pdev,
        struct rsnd_mod_ops *ops;
        struct clk *clk;
        char name[RSND_SRC_NAME_SIZE];
-       int i, nr;
+       int i, nr, ret;
 
        ops = NULL;
        if (rsnd_is_gen1(priv))
@@ -890,10 +890,23 @@ int rsnd_src_probe(struct platform_device *pdev,
 
                src->info = &info->src_info[i];
 
-               rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
+               ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
+               if (ret)
+                       return ret;
 
                dev_dbg(dev, "SRC%d probed\n", i);
        }
 
        return 0;
 }
+
+void rsnd_src_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_src *src;
+       int i;
+
+       for_each_rsnd_src(src, priv, i) {
+               rsnd_mod_quit(&src->mod);
+       }
+}
index 9e7b627..f7cb1fd 100644 (file)
@@ -697,7 +697,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
        struct clk *clk;
        struct rsnd_ssi *ssi;
        char name[RSND_SSI_NAME_SIZE];
-       int i, nr;
+       int i, nr, ret;
 
        rsnd_of_parse_ssi(pdev, of_data, priv);
 
@@ -732,10 +732,23 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                else if (rsnd_ssi_pio_available(ssi))
                        ops = &rsnd_ssi_pio_ops;
 
-               rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i);
+               ret = rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i);
+               if (ret)
+                       return ret;
 
                rsnd_ssi_parent_clk_setup(priv, ssi);
        }
 
        return 0;
 }
+
+void rsnd_ssi_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi;
+       int i;
+
+       for_each_rsnd_ssi(ssi, priv, i) {
+               rsnd_mod_quit(&ssi->mod);
+       }
+}
index 30579ca..2fb3bf7 100644 (file)
@@ -292,6 +292,9 @@ static const struct file_operations codec_reg_fops = {
 
 static void soc_init_component_debugfs(struct snd_soc_component *component)
 {
+       if (!component->card->debugfs_card_root)
+               return;
+
        if (component->debugfs_prefix) {
                char *name;
 
@@ -347,6 +350,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(codec, &codec_list, list) {
                len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
                               codec->component.name);
@@ -358,6 +363,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        if (ret >= 0)
                ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
@@ -382,6 +389,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(component, &component_list, list) {
                list_for_each_entry(dai, &component->dai_list, list) {
                        len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
@@ -395,6 +404,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -418,6 +429,8 @@ static ssize_t platform_list_read_file(struct file *file,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(platform, &platform_list, list) {
                len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
                               platform->component.name);
@@ -429,6 +442,8 @@ static ssize_t platform_list_read_file(struct file *file,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -443,6 +458,9 @@ static const struct file_operations platform_list_fops = {
 
 static void soc_init_card_debugfs(struct snd_soc_card *card)
 {
+       if (!snd_soc_debugfs_root)
+               return;
+
        card->debugfs_card_root = debugfs_create_dir(card->name,
                                                     snd_soc_debugfs_root);
        if (!card->debugfs_card_root) {
@@ -464,6 +482,34 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
        debugfs_remove_recursive(card->debugfs_card_root);
 }
 
+
+static void snd_soc_debugfs_init(void)
+{
+       snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
+       if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
+               pr_warn("ASoC: Failed to create debugfs directory\n");
+               snd_soc_debugfs_root = NULL;
+               return;
+       }
+
+       if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
+                                &codec_list_fops))
+               pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
+
+       if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
+                                &dai_list_fops))
+               pr_warn("ASoC: Failed to create DAI list debugfs file\n");
+
+       if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
+                                &platform_list_fops))
+               pr_warn("ASoC: Failed to create platform list debugfs file\n");
+}
+
+static void snd_soc_debugfs_exit(void)
+{
+       debugfs_remove_recursive(snd_soc_debugfs_root);
+}
+
 #else
 
 #define soc_init_codec_debugfs NULL
@@ -485,6 +531,15 @@ static inline void soc_init_card_debugfs(struct snd_soc_card *card)
 static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
 {
 }
+
+static inline void snd_soc_debugfs_init(void)
+{
+}
+
+static inline void snd_soc_debugfs_exit(void)
+{
+}
+
 #endif
 
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
@@ -583,15 +638,9 @@ int snd_soc_suspend(struct device *dev)
                        cpu_dai->driver->suspend(cpu_dai);
        }
 
-       /* close any waiting streams and save state */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai **codec_dais = card->rtd[i].codec_dais;
+       /* close any waiting streams */
+       for (i = 0; i < card->num_rtd; i++)
                flush_delayed_work(&card->rtd[i].delayed_work);
-               for (j = 0; j < card->rtd[i].num_codecs; j++) {
-                       codec_dais[j]->codec->dapm.suspend_bias_level =
-                                       codec_dais[j]->codec->dapm.bias_level;
-               }
-       }
 
        for (i = 0; i < card->num_rtd; i++) {
 
@@ -836,6 +885,8 @@ static struct snd_soc_component *soc_find_component(
 {
        struct snd_soc_component *component;
 
+       lockdep_assert_held(&client_mutex);
+
        list_for_each_entry(component, &component_list, list) {
                if (of_node) {
                        if (component->dev->of_node == of_node)
@@ -854,6 +905,8 @@ static struct snd_soc_dai *snd_soc_find_dai(
        struct snd_soc_component *component;
        struct snd_soc_dai *dai;
 
+       lockdep_assert_held(&client_mutex);
+
        /* Find CPU DAI from registered DAIs*/
        list_for_each_entry(component, &component_list, list) {
                if (dlc->of_node && component->dev->of_node != dlc->of_node)
@@ -1306,21 +1359,17 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
                }
        }
 
+       if (dai_link->dai_fmt)
+               snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
+
        ret = soc_post_component_init(rtd, dai_link->name);
        if (ret)
                return ret;
 
 #ifdef CONFIG_DEBUG_FS
        /* add DPCM sysfs entries */
-       if (dai_link->dynamic) {
-               ret = soc_dpcm_debugfs_add(rtd);
-               if (ret < 0) {
-                       dev_err(rtd->dev,
-                               "ASoC: failed to add dpcm sysfs entries: %d\n",
-                               ret);
-                       return ret;
-               }
-       }
+       if (dai_link->dynamic)
+               soc_dpcm_debugfs_add(rtd);
 #endif
 
        if (cpu_dai->driver->compress_dai) {
@@ -1410,7 +1459,6 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
 
        /* unregister the rtd device */
        if (rtd->dev_registered) {
-               device_remove_file(rtd->dev, &dev_attr_codec_reg);
                device_unregister(rtd->dev);
                rtd->dev_registered = 0;
        }
@@ -1508,6 +1556,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        struct snd_soc_codec *codec;
        int ret, i, order;
 
+       mutex_lock(&client_mutex);
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
        /* bind DAIs */
@@ -1543,6 +1592,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                goto base_error;
        }
 
+       soc_init_card_debugfs(card);
+
        card->dapm.bias_level = SND_SOC_BIAS_OFF;
        card->dapm.dev = card->dev;
        card->dapm.card = card;
@@ -1561,6 +1612,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
                                          card->num_dapm_widgets);
 
+       if (card->of_dapm_widgets)
+               snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
+                                         card->num_of_dapm_widgets);
+
        /* initialise the sound card only once */
        if (card->probe) {
                ret = card->probe(card);
@@ -1616,11 +1671,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
                                        card->num_dapm_routes);
 
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].dai_fmt)
-                       snd_soc_runtime_set_dai_fmt(&card->rtd[i],
-                               card->dai_link[i].dai_fmt);
-       }
+       if (card->of_dapm_routes)
+               snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
+                                       card->num_of_dapm_routes);
 
        snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
                 "%s", card->name);
@@ -1662,6 +1715,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        card->instantiated = 1;
        snd_soc_dapm_sync(&card->dapm);
        mutex_unlock(&card->mutex);
+       mutex_unlock(&client_mutex);
 
        return 0;
 
@@ -1676,10 +1730,12 @@ card_probe_error:
        if (card->remove)
                card->remove(card);
 
+       soc_cleanup_card_debugfs(card);
        snd_card_free(card->snd_card);
 
 base_error:
        mutex_unlock(&card->mutex);
+       mutex_unlock(&client_mutex);
 
        return ret;
 }
@@ -2353,8 +2409,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
 
        snd_soc_initialize_card_lists(card);
 
-       soc_init_card_debugfs(card);
-
        card->rtd = devm_kzalloc(card->dev,
                                 sizeof(struct snd_soc_pcm_runtime) *
                                 (card->num_links + card->num_aux_devs),
@@ -2385,7 +2439,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
 
        ret = snd_soc_instantiate_card(card);
        if (ret != 0)
-               soc_cleanup_card_debugfs(card);
+               return ret;
 
        /* deactivate pins to sleep state */
        for (i = 0; i < card->num_rtd; i++) {
@@ -2713,13 +2767,6 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
        list_del(&component->list);
 }
 
-static void snd_soc_component_del(struct snd_soc_component *component)
-{
-       mutex_lock(&client_mutex);
-       snd_soc_component_del_unlocked(component);
-       mutex_unlock(&client_mutex);
-}
-
 int snd_soc_register_component(struct device *dev,
                               const struct snd_soc_component_driver *cmpnt_drv,
                               struct snd_soc_dai_driver *dai_drv,
@@ -2767,14 +2814,17 @@ void snd_soc_unregister_component(struct device *dev)
 {
        struct snd_soc_component *cmpnt;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(cmpnt, &component_list, list) {
                if (dev == cmpnt->dev && cmpnt->registered_as_component)
                        goto found;
        }
+       mutex_unlock(&client_mutex);
        return;
 
 found:
-       snd_soc_component_del(cmpnt);
+       snd_soc_component_del_unlocked(cmpnt);
+       mutex_unlock(&client_mutex);
        snd_soc_component_cleanup(cmpnt);
        kfree(cmpnt);
 }
@@ -2882,10 +2932,14 @@ struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
 {
        struct snd_soc_platform *platform;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(platform, &platform_list, list) {
-               if (dev == platform->dev)
+               if (dev == platform->dev) {
+                       mutex_unlock(&client_mutex);
                        return platform;
+               }
        }
+       mutex_unlock(&client_mutex);
 
        return NULL;
 }
@@ -3090,15 +3144,15 @@ void snd_soc_unregister_codec(struct device *dev)
 {
        struct snd_soc_codec *codec;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(codec, &codec_list, list) {
                if (dev == codec->dev)
                        goto found;
        }
+       mutex_unlock(&client_mutex);
        return;
 
 found:
-
-       mutex_lock(&client_mutex);
        list_del(&codec->list);
        snd_soc_component_del_unlocked(&codec->component);
        mutex_unlock(&client_mutex);
@@ -3223,8 +3277,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
                widgets[i].name = wname;
        }
 
-       card->dapm_widgets = widgets;
-       card->num_dapm_widgets = num_widgets;
+       card->of_dapm_widgets = widgets;
+       card->num_of_dapm_widgets = num_widgets;
 
        return 0;
 }
@@ -3308,8 +3362,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                }
        }
 
-       card->num_dapm_routes = num_routes;
-       card->dapm_routes = routes;
+       card->num_of_dapm_routes = num_routes;
+       card->of_dapm_routes = routes;
 
        return 0;
 }
@@ -3568,26 +3622,7 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs);
 
 static int __init snd_soc_init(void)
 {
-#ifdef CONFIG_DEBUG_FS
-       snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
-       if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
-               pr_warn("ASoC: Failed to create debugfs directory\n");
-               snd_soc_debugfs_root = NULL;
-       }
-
-       if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
-                                &codec_list_fops))
-               pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
-
-       if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
-                                &dai_list_fops))
-               pr_warn("ASoC: Failed to create DAI list debugfs file\n");
-
-       if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
-                                &platform_list_fops))
-               pr_warn("ASoC: Failed to create platform list debugfs file\n");
-#endif
-
+       snd_soc_debugfs_init();
        snd_soc_util_init();
 
        return platform_driver_register(&soc_driver);
@@ -3597,9 +3632,9 @@ module_init(snd_soc_init);
 static void __exit snd_soc_exit(void)
 {
        snd_soc_util_exit();
+       snd_soc_debugfs_exit();
 
 #ifdef CONFIG_DEBUG_FS
-       debugfs_remove_recursive(snd_soc_debugfs_root);
 #endif
        platform_driver_unregister(&soc_driver);
 }
index b6f8820..dc05469 100644 (file)
@@ -473,16 +473,6 @@ struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
 
-/**
- * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
- * @kcontrol: The kcontrol
- */
-struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol)
-{
-       return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol));
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec);
-
 static void dapm_reset(struct snd_soc_card *card)
 {
        struct snd_soc_dapm_widget *w;
@@ -1898,6 +1888,9 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
 {
        struct dentry *d;
 
+       if (!parent)
+               return;
+
        dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
 
        if (!dapm->debugfs_dapm) {
index 4380dcc..9f60c25 100644 (file)
 #include <trace/events/asoc.h>
 
 /**
- * snd_soc_jack_new - Create a new jack
- * @codec: ASoC codec
+ * snd_soc_card_jack_new - Create a new jack
+ * @card:  ASoC card
  * @id:    an identifying string for this jack
  * @type:  a bitmask of enum snd_jack_type values that can be detected by
  *         this jack
  * @jack:  structure to use for the jack
+ * @pins:  Array of jack pins to be added to the jack or NULL
+ * @num_pins: Number of elements in the @pins array
  *
  * Creates a new jack object.
  *
  * Returns zero if successful, or a negative error code on failure.
  * On success jack will be initialised.
  */
-int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
-                    struct snd_soc_jack *jack)
+int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
+       struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
+       unsigned int num_pins)
 {
+       int ret;
+
        mutex_init(&jack->mutex);
-       jack->codec = codec;
+       jack->card = card;
        INIT_LIST_HEAD(&jack->pins);
        INIT_LIST_HEAD(&jack->jack_zones);
        BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
 
-       return snd_jack_new(codec->component.card->snd_card, id, type, &jack->jack);
+       ret = snd_jack_new(card->snd_card, id, type, &jack->jack);
+       if (ret)
+               return ret;
+
+       if (num_pins)
+               return snd_soc_jack_add_pins(jack, num_pins, pins);
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_jack_new);
+EXPORT_SYMBOL_GPL(snd_soc_card_jack_new);
 
 /**
  * snd_soc_jack_report - Report the current status for a jack
@@ -63,7 +75,6 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_new);
  */
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
 {
-       struct snd_soc_codec *codec;
        struct snd_soc_dapm_context *dapm;
        struct snd_soc_jack_pin *pin;
        unsigned int sync = 0;
@@ -74,8 +85,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        if (!jack)
                return;
 
-       codec = jack->codec;
-       dapm =  &codec->dapm;
+       dapm = &jack->card->dapm;
 
        mutex_lock(&jack->mutex);
 
@@ -175,12 +185,12 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
 
        for (i = 0; i < count; i++) {
                if (!pins[i].pin) {
-                       dev_err(jack->codec->dev, "ASoC: No name for pin %d\n",
+                       dev_err(jack->card->dev, "ASoC: No name for pin %d\n",
                                i);
                        return -EINVAL;
                }
                if (!pins[i].mask) {
-                       dev_err(jack->codec->dev, "ASoC: No mask for pin %d"
+                       dev_err(jack->card->dev, "ASoC: No mask for pin %d"
                                " (%s)\n", i, pins[i].pin);
                        return -EINVAL;
                }
@@ -260,7 +270,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
 static irqreturn_t gpio_handler(int irq, void *data)
 {
        struct snd_soc_jack_gpio *gpio = data;
-       struct device *dev = gpio->jack->codec->component.card->dev;
+       struct device *dev = gpio->jack->card->dev;
 
        trace_snd_soc_jack_irq(gpio->name);
 
@@ -299,7 +309,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 
        for (i = 0; i < count; i++) {
                if (!gpios[i].name) {
-                       dev_err(jack->codec->dev,
+                       dev_err(jack->card->dev,
                                "ASoC: No name for gpio at index %d\n", i);
                        ret = -EINVAL;
                        goto undo;
@@ -320,7 +330,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                } else {
                        /* legacy GPIO number */
                        if (!gpio_is_valid(gpios[i].gpio)) {
-                               dev_err(jack->codec->dev,
+                               dev_err(jack->card->dev,
                                        "ASoC: Invalid gpio %d\n",
                                        gpios[i].gpio);
                                ret = -EINVAL;
@@ -350,7 +360,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                if (gpios[i].wake) {
                        ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1);
                        if (ret != 0)
-                               dev_err(jack->codec->dev,
+                               dev_err(jack->card->dev,
                                        "ASoC: Failed to mark GPIO at index %d as wake source: %d\n",
                                        i, ret);
                }
index 6b0136e..35fe58f 100644 (file)
@@ -1097,8 +1097,9 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
                        stream ? "<-" : "->", be->dai_link->name);
 
 #ifdef CONFIG_DEBUG_FS
-       dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
-                       fe->debugfs_dpcm_root, &dpcm->state);
+       if (fe->debugfs_dpcm_root)
+               dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
+                               fe->debugfs_dpcm_root, &dpcm->state);
 #endif
        return 1;
 }
@@ -2511,6 +2512,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
        /* DAPM dai link stream work */
        INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 
+       pcm->nonatomic = rtd->dai_link->nonatomic;
        rtd->pcm = pcm;
        pcm->private_data = rtd;
 
@@ -2802,10 +2804,13 @@ static const struct file_operations dpcm_state_fops = {
        .llseek = default_llseek,
 };
 
-int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
+void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
 {
        if (!rtd->dai_link)
-               return 0;
+               return;
+
+       if (!rtd->card->debugfs_card_root)
+               return;
 
        rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
                        rtd->card->debugfs_card_root);
@@ -2813,13 +2818,11 @@ int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
                dev_dbg(rtd->dev,
                         "ASoC: Failed to create dpcm debugfs directory %s\n",
                         rtd->dai_link->name);
-               return -EINVAL;
+               return;
        }
 
        rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444,
                                                rtd->debugfs_dpcm_root,
                                                rtd, &dpcm_state_fops);
-
-       return 0;
 }
 #endif
index 769aca2..6dcd06a 100644 (file)
@@ -106,11 +106,10 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card);
 
-       snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
-                        &tegra_alc5632_hs_jack);
-       snd_soc_jack_add_pins(&tegra_alc5632_hs_jack,
-                       ARRAY_SIZE(tegra_alc5632_hs_jack_pins),
-                       tegra_alc5632_hs_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
+                             &tegra_alc5632_hs_jack,
+                             tegra_alc5632_hs_jack_pins,
+                             ARRAY_SIZE(tegra_alc5632_hs_jack_pins));
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
index af3fb99..902da36 100644 (file)
@@ -133,24 +133,26 @@ static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_SPK("Speakers", NULL),
        SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
 };
 
 static const struct snd_kcontrol_new tegra_max98090_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphones"),
        SOC_DAPM_PIN_SWITCH("Speakers"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
 };
 
 static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = codec_dai->codec;
        struct tegra_max98090 *machine = snd_soc_card_get_drvdata(rtd->card);
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
-               snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
-                               &tegra_max98090_hp_jack);
-               snd_soc_jack_add_pins(&tegra_max98090_hp_jack,
-                               ARRAY_SIZE(tegra_max98090_hp_jack_pins),
-                               tegra_max98090_hp_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Headphones",
+                                     SND_JACK_HEADPHONE,
+                                     &tegra_max98090_hp_jack,
+                                     tegra_max98090_hp_jack_pins,
+                                     ARRAY_SIZE(tegra_max98090_hp_jack_pins));
 
                tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det;
                snd_soc_jack_add_gpios(&tegra_max98090_hp_jack,
@@ -159,11 +161,11 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        if (gpio_is_valid(machine->gpio_mic_det)) {
-               snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
-                                &tegra_max98090_mic_jack);
-               snd_soc_jack_add_pins(&tegra_max98090_mic_jack,
-                                     ARRAY_SIZE(tegra_max98090_mic_jack_pins),
-                                     tegra_max98090_mic_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Mic Jack",
+                                     SND_JACK_MICROPHONE,
+                                     &tegra_max98090_mic_jack,
+                                     tegra_max98090_mic_jack_pins,
+                                     ARRAY_SIZE(tegra_max98090_mic_jack_pins));
 
                tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det;
                snd_soc_jack_add_gpios(&tegra_max98090_mic_jack,
index ed759a3..773daec 100644 (file)
@@ -108,15 +108,11 @@ static const struct snd_kcontrol_new tegra_rt5640_controls[] = {
 
 static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = codec_dai->codec;
        struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(rtd->card);
 
-       snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
-                        &tegra_rt5640_hp_jack);
-       snd_soc_jack_add_pins(&tegra_rt5640_hp_jack,
-                       ARRAY_SIZE(tegra_rt5640_hp_jack_pins),
-                       tegra_rt5640_hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphones", SND_JACK_HEADPHONE,
+                             &tegra_rt5640_hp_jack, tegra_rt5640_hp_jack_pins,
+                             ARRAY_SIZE(tegra_rt5640_hp_jack_pins));
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det;
index e4cf978..68d8b67 100644 (file)
@@ -146,10 +146,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card);
 
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-                       &tegra_rt5677_hp_jack);
-       snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1,
-                       &tegra_rt5677_hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
+                             &tegra_rt5677_hp_jack,
+                             &tegra_rt5677_hp_jack_pins, 1);
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det;
@@ -158,10 +157,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
        }
 
 
-       snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
-                       &tegra_rt5677_mic_jack);
-       snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1,
-                       &tegra_rt5677_mic_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE,
+                             &tegra_rt5677_mic_jack,
+                             &tegra_rt5677_mic_jack_pins, 1);
 
        if (gpio_is_valid(machine->gpio_mic_present)) {
                tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present;
index e52420d..4a95b70 100644 (file)
@@ -177,21 +177,19 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det;
-               snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-                               &tegra_wm8903_hp_jack);
-               snd_soc_jack_add_pins(&tegra_wm8903_hp_jack,
-                                       ARRAY_SIZE(tegra_wm8903_hp_jack_pins),
-                                       tegra_wm8903_hp_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+                                     SND_JACK_HEADPHONE, &tegra_wm8903_hp_jack,
+                                     tegra_wm8903_hp_jack_pins,
+                                     ARRAY_SIZE(tegra_wm8903_hp_jack_pins));
                snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
                                        1,
                                        &tegra_wm8903_hp_jack_gpio);
        }
 
-       snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
-                        &tegra_wm8903_mic_jack);
-       snd_soc_jack_add_pins(&tegra_wm8903_mic_jack,
-                             ARRAY_SIZE(tegra_wm8903_mic_jack_pins),
-                             tegra_wm8903_mic_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE,
+                             &tegra_wm8903_mic_jack,
+                             tegra_wm8903_mic_jack_pins,
+                             ARRAY_SIZE(tegra_wm8903_mic_jack_pins));
        wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
                                0);
 
index 05dee69..97ed593 100644 (file)
@@ -39,7 +39,7 @@ static void change_volume(struct urb *urb_out, int volume[],
                for (; p < buf_end; ++p) {
                        short pv = le16_to_cpu(*p);
                        int val = (pv * volume[chn & 1]) >> 8;
-                       pv = clamp(val, 0x7fff, -0x8000);
+                       pv = clamp(val, -0x8000, 0x7fff);
                        *p = cpu_to_le16(pv);
                        ++chn;
                }
@@ -54,7 +54,7 @@ static void change_volume(struct urb *urb_out, int volume[],
 
                        val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
                        val = (val * volume[chn & 1]) >> 8;
-                       val = clamp(val, 0x7fffff, -0x800000);
+                       val = clamp(val, -0x800000, 0x7fffff);
                        p[0] = val;
                        p[1] = val >> 8;
                        p[2] = val >> 16;
@@ -126,7 +126,7 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
                        short pov = le16_to_cpu(*po);
                        short piv = le16_to_cpu(*pi);
                        int val = pov + ((piv * volume) >> 8);
-                       pov = clamp(val, 0x7fff, -0x8000);
+                       pov = clamp(val, -0x8000, 0x7fff);
                        *po = cpu_to_le16(pov);
                }
        }
index 67d4765..07f984d 100644 (file)
@@ -1773,6 +1773,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x0582, 0x0159),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "UA-22", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 /* this catches most recent vendor-specific Roland devices */
 {
        .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
index 6c14afe..db1d3a2 100644 (file)
@@ -289,7 +289,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault)
        memcpy_t fn = r->fn.memcpy;
        int i;
 
-       memcpy_alloc_mem(&src, &dst, len);
+       memcpy_alloc_mem(&dst, &src, len);
 
        if (prefault)
                fn(dst, src, len);
@@ -312,7 +312,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len,
        void *src = NULL, *dst = NULL;
        int i;
 
-       memcpy_alloc_mem(&src, &dst, len);
+       memcpy_alloc_mem(&dst, &src, len);
 
        if (prefault)
                fn(dst, src, len);
index ff95a68..ac8721f 100644 (file)
@@ -21,6 +21,10 @@ ifeq ($(RAW_ARCH),x86_64)
   endif
 endif
 
+ifeq ($(RAW_ARCH),sparc64)
+  ARCH ?= sparc
+endif
+
 ARCH ?= $(RAW_ARCH)
 
 LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
index 42ac05a..b32ff33 100644 (file)
@@ -49,7 +49,7 @@ test-hello.bin:
        $(BUILD)
 
 test-pthread-attr-setaffinity-np.bin:
-       $(BUILD) -Werror -lpthread
+       $(BUILD) -D_GNU_SOURCE -Werror -lpthread
 
 test-stackprotector-all.bin:
        $(BUILD) -Werror -fstack-protector-all
index 0a0d3ec..2b81b72 100644 (file)
@@ -5,10 +5,11 @@ int main(void)
 {
        int ret = 0;
        pthread_attr_t thread_attr;
+       cpu_set_t cs;
 
        pthread_attr_init(&thread_attr);
        /* don't care abt exact args, just the API itself in libpthread */
-       ret = pthread_attr_setaffinity_np(&thread_attr, 0, NULL);
+       ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cs), &cs);
 
        return ret;
 }
index 61bf912..9d9db3b 100644 (file)
@@ -30,6 +30,8 @@ static int disasm_line__parse(char *line, char **namep, char **rawp);
 
 static void ins__delete(struct ins_operands *ops)
 {
+       if (ops == NULL)
+               return;
        zfree(&ops->source.raw);
        zfree(&ops->source.name);
        zfree(&ops->target.raw);
index 47b78b3..6da965b 100644 (file)
@@ -25,6 +25,10 @@ static int perf_flag_probe(void)
        if (cpu < 0)
                cpu = 0;
 
+       /*
+        * Using -1 for the pid is a workaround to avoid gratuitous jump label
+        * changes.
+        */
        while (1) {
                /* check cloexec flag */
                fd = sys_perf_event_open(&attr, pid, cpu, -1,
@@ -47,16 +51,24 @@ static int perf_flag_probe(void)
                  err, strerror_r(err, sbuf, sizeof(sbuf)));
 
        /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-       fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
+       while (1) {
+               fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
+               if (fd < 0 && pid == -1 && errno == EACCES) {
+                       pid = 0;
+                       continue;
+               }
+               break;
+       }
        err = errno;
 
+       if (fd >= 0)
+               close(fd);
+
        if (WARN_ONCE(fd < 0 && err != EBUSY,
                      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
                      err, strerror_r(err, sbuf, sizeof(sbuf))))
                return -1;
 
-       close(fd);
-
        return 0;
 }
 
index c94a9e0..e99a676 100644 (file)
@@ -28,7 +28,7 @@ struct perf_mmap {
        int              mask;
        int              refcnt;
        unsigned int     prev;
-       char             event_copy[PERF_SAMPLE_MAX_SIZE];
+       char             event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
 };
 
 struct perf_evlist {
index b24f9d8..33b7a2a 100644 (file)
 #include <symbol/kallsyms.h>
 #include "debug.h"
 
+#ifndef EM_AARCH64
+#define EM_AARCH64     183  /* ARM 64 bit */
+#endif
+
+
 #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
 extern char *cplus_demangle(const char *, int);
 
index 3ed7c04..2e2ba2e 100644 (file)
@@ -209,7 +209,7 @@ $(OUTPUT)%.o: %.c
 
 $(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ)
        $(ECHO) "  CC      " $@
-       $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -Wl,-rpath=./ -lrt -lpci -L$(OUTPUT) -o $@
+       $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@
        $(QUIET) $(STRIPCMD) $@
 
 $(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC)
index 4e51122..0db5713 100644 (file)
@@ -22,6 +22,14 @@ TARGETS += vm
 TARGETS_HOTPLUG = cpu-hotplug
 TARGETS_HOTPLUG += memory-hotplug
 
+# Clear LDFLAGS and MAKEFLAGS if called from main
+# Makefile to avoid test build failures when test
+# Makefile doesn't have explicit build rules.
+ifeq (1,$(MAKELEVEL))
+undefine LDFLAGS
+override MAKEFLAGS =
+endif
+
 all:
        for TARGET in $(TARGETS); do \
                make -C $$TARGET; \
index e238c95..8d5d1d2 100644 (file)
@@ -30,7 +30,7 @@ static int execveat_(int fd, const char *path, char **argv, char **envp,
 #ifdef __NR_execveat
        return syscall(__NR_execveat, fd, path, argv, envp, flags);
 #else
-       errno = -ENOSYS;
+       errno = ENOSYS;
        return -1;
 #endif
 }
@@ -234,6 +234,14 @@ static int run_tests(void)
        int fd_cloexec = open_or_die("execveat", O_RDONLY|O_CLOEXEC);
        int fd_script_cloexec = open_or_die("script", O_RDONLY|O_CLOEXEC);
 
+       /* Check if we have execveat at all, and bail early if not */
+       errno = 0;
+       execveat_(-1, NULL, NULL, NULL, 0);
+       if (errno == ENOSYS) {
+               printf("[FAIL] ENOSYS calling execveat - no kernel support?\n");
+               return 1;
+       }
+
        /* Change file position to confirm it doesn't affect anything */
        lseek(fd, 10, SEEK_SET);
 
diff --git a/tools/thermal/tmon/.gitignore b/tools/thermal/tmon/.gitignore
new file mode 100644 (file)
index 0000000..06e96be
--- /dev/null
@@ -0,0 +1 @@
+/tmon
index e775adc..0788621 100644 (file)
@@ -2,8 +2,8 @@ VERSION = 1.0
 
 BINDIR=usr/bin
 WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
-CFLAGS= -O1 ${WARNFLAGS} -fstack-protector
-CC=gcc
+CFLAGS+= -O1 ${WARNFLAGS} -fstack-protector
+CC=$(CROSS_COMPILE)gcc
 
 CFLAGS+=-D VERSION=\"$(VERSION)\"
 LDFLAGS+=
@@ -16,12 +16,21 @@ INSTALL_CONFIGFILE=install -m 644 -p
 CONFIG_FILE=
 CONFIG_PATH=
 
+# Static builds might require -ltinfo, for instance
+ifneq ($(findstring -static, $(LDFLAGS)),)
+STATIC := --static
+endif
+
+TMON_LIBS=-lm -lpthread
+TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || \
+                    pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \
+                    echo -lpanel -lncurses)
 
 OBJS = tmon.o tui.o sysfs.o pid.o
 OBJS +=
 
 tmon: $(OBJS) Makefile tmon.h
-       $(CC) ${CFLAGS} $(LDFLAGS) $(OBJS)  -o $(TARGET) -lm -lpanel -lncursesw -ltinfo -lpthread
+       $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS)  -o $(TARGET) $(TMON_LIBS)
 
 valgrind: tmon
         sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET)  1> /dev/null
index 0be727c..02d5179 100644 (file)
@@ -55,6 +55,8 @@ The \fB-l --log\fP option write data to /var/tmp/tmon.log
 .PP
 The \fB-t --time-interval\fP option sets the polling interval in seconds
 .PP
+The \fB-T --target-temp\fP option sets the initial target temperature
+.PP
 The \fB-v --version\fP option shows the version of \fBtmon \fP
 .PP
 The \fB-z --zone\fP option sets the target therma zone instance to be controlled
index 09b7c32..9aa1965 100644 (file)
@@ -64,6 +64,7 @@ void usage()
        printf("  -h, --help            show this help message\n");
        printf("  -l, --log             log data to /var/tmp/tmon.log\n");
        printf("  -t, --time-interval   sampling time interval, > 1 sec.\n");
+       printf("  -T, --target-temp     initial target temperature\n");
        printf("  -v, --version         show version\n");
        printf("  -z, --zone            target thermal zone id\n");
 
@@ -219,6 +220,7 @@ static struct option opts[] = {
        { "control", 1, NULL, 'c' },
        { "daemon", 0, NULL, 'd' },
        { "time-interval", 1, NULL, 't' },
+       { "target-temp", 1, NULL, 'T' },
        { "log", 0, NULL, 'l' },
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'v' },
@@ -231,7 +233,7 @@ int main(int argc, char **argv)
 {
        int err = 0;
        int id2 = 0, c;
-       double yk = 0.0; /* controller output */
+       double yk = 0.0, temp; /* controller output */
        int target_tz_index;
 
        if (geteuid() != 0) {
@@ -239,7 +241,7 @@ int main(int argc, char **argv)
                exit(EXIT_FAILURE);
        }
 
-       while ((c = getopt_long(argc, argv, "c:dlht:vgz:", opts, &id2)) != -1) {
+       while ((c = getopt_long(argc, argv, "c:dlht:T:vgz:", opts, &id2)) != -1) {
                switch (c) {
                case 'c':
                        no_control = 0;
@@ -254,6 +256,14 @@ int main(int argc, char **argv)
                        if (ticktime < 1)
                                ticktime = 1;
                        break;
+               case 'T':
+                       temp = strtod(optarg, NULL);
+                       if (temp < 0) {
+                               fprintf(stderr, "error: temperature must be positive\n");
+                               return 1;
+                       }
+                       target_temp_user = temp;
+                       break;
                case 'l':
                        printf("Logging data to /var/tmp/tmon.log\n");
                        logging = 1;
index 89f8ef0..b5d1c6b 100644 (file)
 
 #include "tmon.h"
 
+#define min(x, y) ({                           \
+       typeof(x) _min1 = (x);                  \
+       typeof(y) _min2 = (y);                  \
+       (void) (&_min1 == &_min2);              \
+       _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({                           \
+       typeof(x) _max1 = (x);                  \
+       typeof(y) _max2 = (y);                  \
+       (void) (&_max1 == &_max2);              \
+       _max1 > _max2 ? _max1 : _max2; })
+
 static PANEL *data_panel;
 static PANEL *dialogue_panel;
 static PANEL *top;
@@ -98,6 +110,18 @@ void write_status_bar(int x, char *line)
        wrefresh(status_bar_window);
 }
 
+/* wrap at 5 */
+#define DIAG_DEV_ROWS  5
+/*
+ * list cooling devices + "set temp" entry; wraps after 5 rows, if they fit
+ */
+static int diag_dev_rows(void)
+{
+       int entries = ptdata.nr_cooling_dev + 1;
+       int rows = max(DIAG_DEV_ROWS, (entries + 1) / 2);
+       return min(rows, entries);
+}
+
 void setup_windows(void)
 {
        int y_begin = 1;
@@ -122,7 +146,7 @@ void setup_windows(void)
         * dialogue window is a pop-up, when needed it lays on top of cdev win
         */
 
-       dialogue_window = subwin(stdscr, ptdata.nr_cooling_dev+5, maxx-50,
+       dialogue_window = subwin(stdscr, diag_dev_rows() + 5, maxx-50,
                                DIAG_Y, DIAG_X);
 
        thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor *
@@ -258,21 +282,26 @@ void show_cooling_device(void)
 }
 
 const char DIAG_TITLE[] = "[ TUNABLES ]";
-#define DIAG_DEV_ROWS  5
 void show_dialogue(void)
 {
        int j, x = 0, y = 0;
+       int rows, cols;
        WINDOW *w = dialogue_window;
 
        if (tui_disabled || !w)
                return;
 
+       getmaxyx(w, rows, cols);
+
+       /* Silence compiler 'unused' warnings */
+       (void)cols;
+
        werase(w);
        box(w, 0, 0);
        mvwprintw(w, 0, maxx/4, DIAG_TITLE);
        /* list all the available tunables */
        for (j = 0; j <= ptdata.nr_cooling_dev; j++) {
-               y = j % DIAG_DEV_ROWS;
+               y = j % diag_dev_rows();
                if (y == 0 && j != 0)
                        x += 20;
                if (j == ptdata.nr_cooling_dev)
@@ -283,12 +312,10 @@ void show_dialogue(void)
                                ptdata.cdi[j].type, ptdata.cdi[j].instance);
        }
        wattron(w, A_BOLD);
-       mvwprintw(w, DIAG_DEV_ROWS+1, 1, "Enter Choice [A-Z]?");
+       mvwprintw(w, diag_dev_rows()+1, 1, "Enter Choice [A-Z]?");
        wattroff(w, A_BOLD);
-       /* y size of dialogue win is nr cdev + 5, so print legend
-        * at the bottom line
-        */
-       mvwprintw(w, ptdata.nr_cooling_dev+3, 1,
+       /* print legend at the bottom line */
+       mvwprintw(w, rows - 2, 1,
                "Legend: A=Active, P=Passive, C=Critical");
 
        wrefresh(dialogue_window);
@@ -437,7 +464,7 @@ static void handle_input_choice(int ch)
                        snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ",
                                ptdata.cdi[cdev_id].type,
                                ptdata.cdi[cdev_id].instance);
-               write_dialogue_win(buf, DIAG_DEV_ROWS+2, 2);
+               write_dialogue_win(buf, diag_dev_rows() + 2, 2);
                handle_input_val(cdev_id);
        } else {
                snprintf(buf, sizeof(buf), "Invalid selection %d", ch);
index a0a7b5d..f9b9c7c 100644 (file)
@@ -72,6 +72,8 @@ static void vgic_v2_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
 {
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr |= (1ULL << lr);
+       else
+               vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr &= ~(1ULL << lr);
 }
 
 static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
@@ -84,6 +86,11 @@ static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr;
 }
 
+static void vgic_v2_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr = 0;
+}
+
 static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)
 {
        u32 misr = vcpu->arch.vgic_cpu.vgic_v2.vgic_misr;
@@ -148,6 +155,7 @@ static const struct vgic_ops vgic_v2_ops = {
        .sync_lr_elrsr          = vgic_v2_sync_lr_elrsr,
        .get_elrsr              = vgic_v2_get_elrsr,
        .get_eisr               = vgic_v2_get_eisr,
+       .clear_eisr             = vgic_v2_clear_eisr,
        .get_interrupt_status   = vgic_v2_get_interrupt_status,
        .enable_underflow       = vgic_v2_enable_underflow,
        .disable_underflow      = vgic_v2_disable_underflow,
index 3a62d8a..dff0602 100644 (file)
@@ -104,6 +104,8 @@ static void vgic_v3_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
 {
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
+       else
+               vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr &= ~(1U << lr);
 }
 
 static u64 vgic_v3_get_elrsr(const struct kvm_vcpu *vcpu)
@@ -116,6 +118,11 @@ static u64 vgic_v3_get_eisr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr;
 }
 
+static void vgic_v3_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr = 0;
+}
+
 static u32 vgic_v3_get_interrupt_status(const struct kvm_vcpu *vcpu)
 {
        u32 misr = vcpu->arch.vgic_cpu.vgic_v3.vgic_misr;
@@ -192,6 +199,7 @@ static const struct vgic_ops vgic_v3_ops = {
        .sync_lr_elrsr          = vgic_v3_sync_lr_elrsr,
        .get_elrsr              = vgic_v3_get_elrsr,
        .get_eisr               = vgic_v3_get_eisr,
+       .clear_eisr             = vgic_v3_clear_eisr,
        .get_interrupt_status   = vgic_v3_get_interrupt_status,
        .enable_underflow       = vgic_v3_enable_underflow,
        .disable_underflow      = vgic_v3_disable_underflow,
index 0cc6ab6..c9f60f5 100644 (file)
@@ -883,6 +883,11 @@ static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
        return vgic_ops->get_eisr(vcpu);
 }
 
+static inline void vgic_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vgic_ops->clear_eisr(vcpu);
+}
+
 static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)
 {
        return vgic_ops->get_interrupt_status(vcpu);
@@ -922,6 +927,7 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
        vgic_set_lr(vcpu, lr_nr, vlr);
        clear_bit(lr_nr, vgic_cpu->lr_used);
        vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
+       vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
 }
 
 /*
@@ -978,6 +984,7 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                        BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
                        vlr.state |= LR_STATE_PENDING;
                        vgic_set_lr(vcpu, lr, vlr);
+                       vgic_sync_lr_elrsr(vcpu, lr, vlr);
                        return true;
                }
        }
@@ -999,6 +1006,7 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                vlr.state |= LR_EOI_INT;
 
        vgic_set_lr(vcpu, lr, vlr);
+       vgic_sync_lr_elrsr(vcpu, lr, vlr);
 
        return true;
 }
@@ -1136,6 +1144,14 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
        if (status & INT_STATUS_UNDERFLOW)
                vgic_disable_underflow(vcpu);
 
+       /*
+        * In the next iterations of the vcpu loop, if we sync the vgic state
+        * after flushing it, but before entering the guest (this happens for
+        * pending signals and vmid rollovers), then make sure we don't pick
+        * up any old maintenance interrupts here.
+        */
+       vgic_clear_eisr(vcpu);
+
        return level_pending;
 }
 
@@ -1583,8 +1599,10 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
         * emulation. So check this here again. KVM_CREATE_DEVICE does
         * the proper checks already.
         */
-       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2)
-               return -ENODEV;
+       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2) {
+               ret = -ENODEV;
+               goto out;
+       }
 
        /*
         * Any time a vcpu is run, vcpu_load is called which tries to grab the
index a109370..cc6a25d 100644 (file)
@@ -471,7 +471,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
        BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
 
        r = -ENOMEM;
-       kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+       kvm->memslots = kvm_kvzalloc(sizeof(struct kvm_memslots));
        if (!kvm->memslots)
                goto out_err_no_srcu;
 
@@ -522,7 +522,7 @@ out_err_no_srcu:
 out_err_no_disable:
        for (i = 0; i < KVM_NR_BUSES; i++)
                kfree(kvm->buses[i]);
-       kfree(kvm->memslots);
+       kvfree(kvm->memslots);
        kvm_arch_free_vm(kvm);
        return ERR_PTR(r);
 }
@@ -578,7 +578,7 @@ static void kvm_free_physmem(struct kvm *kvm)
        kvm_for_each_memslot(memslot, slots)
                kvm_free_physmem_slot(kvm, memslot, NULL);
 
-       kfree(kvm->memslots);
+       kvfree(kvm->memslots);
 }
 
 static void kvm_destroy_devices(struct kvm *kvm)
@@ -871,10 +871,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
                        goto out_free;
        }
 
-       slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots),
-                       GFP_KERNEL);
+       slots = kvm_kvzalloc(sizeof(struct kvm_memslots));
        if (!slots)
                goto out_free;
+       memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
 
        if ((change == KVM_MR_DELETE) || (change == KVM_MR_MOVE)) {
                slot = id_to_memslot(slots, mem->slot);
@@ -917,7 +917,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        kvm_arch_commit_memory_region(kvm, mem, &old, change);
 
        kvm_free_physmem_slot(kvm, &old, &new);
-       kfree(old_memslots);
+       kvfree(old_memslots);
 
        /*
         * IOMMU mapping:  New slots need to be mapped.  Old slots need to be
@@ -936,7 +936,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        return 0;
 
 out_slots:
-       kfree(slots);
+       kvfree(slots);
 out_free:
        kvm_free_physmem_slot(kvm, &new, &old);
 out:
@@ -2492,6 +2492,7 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
        case KVM_CAP_SIGNAL_MSI:
 #endif
 #ifdef CONFIG_HAVE_KVM_IRQFD
+       case KVM_CAP_IRQFD:
        case KVM_CAP_IRQFD_RESAMPLE:
 #endif
        case KVM_CAP_CHECK_EXTENSION_VM: