Merge remote-tracking branches 'asoc/topic/link-param', 'asoc/topic/max98090', 'asoc...
authorMark Brown <broonie@kernel.org>
Sun, 12 Apr 2015 18:49:06 +0000 (19:49 +0100)
committerMark Brown <broonie@kernel.org>
Sun, 12 Apr 2015 18:49:06 +0000 (19:49 +0100)
1366 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/ingenic,jz4740-i2s.txt
Documentation/devicetree/bindings/sound/max98925.txt [new file with mode: 0644]
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/of-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/arizona.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs4265.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/da732x.c
sound/soc/codecs/es8328.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/max98925.c [new file with mode: 0644]
sound/soc/codecs/max98925.h [new file with mode: 0644]
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/wm5102.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/Kconfig
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/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/pcm030-audio-fabric.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/jz4740/jz4740-i2s.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/nuc900/nuc900-audio.h
sound/soc/nuc900/nuc900-pcm.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/fsi.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 71daa35ec2d9201d2a4647e0a088af3ab36bbae3..eb102fb722134758a39d7d2e17c1dd00fdc0d799 100644 (file)
@@ -404,8 +404,8 @@ supported and the interface files "release_agent" and
   be understood as an underflow into the highest possible value, -2 or
   -10M etc. do not work, so it's not consistent.
 
-  memory.low, memory.high, and memory.max will use the string
-  "infinity" to indicate and set the highest possible value.
+  memory.low, memory.high, and memory.max will use the string "max" to
+  indicate and set the highest possible value.
 
 5. Planned Changes
 
index f4445e5a2bbb7db23a7c32075f2efb5dbb9dec8d..1e097037349c326a22e3f07abb3e3aca9d78d0ce 100644 (file)
@@ -22,6 +22,8 @@ Optional Properties:
        - pclkN, clkN: Pairs of parent of input clock and input clock to the
                devices in this power domain. Maximum of 4 pairs (N = 0 to 3)
                are supported currently.
+- power-domains: phandle pointing to the parent power domain, for more details
+                see Documentation/devicetree/bindings/power/power_domain.txt
 
 Node of a device using power domains must have a power-domains property
 defined with a phandle to respective power domain.
index d70ec358736c48f376020183869d5b582bf81bed..8d27f6b084c7bfd07fda2ffce59c18e9a76390f2 100644 (file)
@@ -13,6 +13,10 @@ Boards with the ST STiH407 SoC shall have the following properties:
 Required root node property:
 compatible = "st,stih407";
 
+Boards with the ST STiH410 SoC shall have the following properties:
+Required root node property:
+compatible = "st,stih410";
+
 Boards with the ST STiH418 SoC shall have the following properties:
 Required root node property:
 compatible = "st,stih418";
index 52d37fd8d3e5c151471a70fb45ff2d4a09317a18..ce4311d726ae5e4a414e6240cc8832e876a9c24e 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
   - "fsl,vf610-i2c" for I2C compatible with the one integrated on Vybrid vf610 SoC
 - reg : Should contain I2C/HS-I2C registers location and length
 - interrupts : Should contain I2C/HS-I2C interrupt
+- clocks : Should contain the I2C/HS-I2C clock specifier
 
 Optional properties:
 - clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
index 33df3932168e1b8941a5de1565b1cf02f96fb551..8db32384a4866e56094aa96e86ac8765ccdf519c 100644 (file)
@@ -27,6 +27,8 @@ property is used.
 - amd,serdes-cdr-rate: CDR rate speed selection
 - amd,serdes-pq-skew: PQ (data sampling) skew
 - amd,serdes-tx-amp: TX amplitude boost
+- amd,serdes-dfe-tap-config: DFE taps available to run
+- amd,serdes-dfe-tap-enable: DFE taps to enable
 
 Example:
        xgbe_phy@e1240800 {
@@ -41,4 +43,6 @@ Example:
                amd,serdes-cdr-rate = <2>, <2>, <7>;
                amd,serdes-pq-skew = <10>, <10>, <30>;
                amd,serdes-tx-amp = <15>, <15>, <10>;
+               amd,serdes-dfe-tap-config = <3>, <3>, <1>;
+               amd,serdes-dfe-tap-enable = <0>, <0>, <127>;
        };
index cfcc52705ed8093ba11b4f549dd1b02a8949fb40..6151999c5dcae6e31f60dc155b433723550cf693 100644 (file)
@@ -4,7 +4,10 @@ Ethernet nodes are defined to describe on-chip ethernet interfaces in
 APM X-Gene SoC.
 
 Required properties for all the ethernet interfaces:
-- compatible: Should be "apm,xgene-enet"
+- compatible: Should state binding information from the following list,
+  - "apm,xgene-enet":    RGMII based 1G interface
+  - "apm,xgene1-sgenet": SGMII based 1G interface
+  - "apm,xgene1-xgenet": XFI based 10G interface
 - reg: Address and length of the register set for the device. It contains the
   information of registers in the same order as described by reg-names
 - reg-names: Should contain the register set names
index e124847443f87c9465ec82dc03ce792d2d1cf5c4..f0b4cd72411d66bf12aeec3d64335d6641b26674 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 98c16672ab5f49e06cd6dd516f3c1a302e65beec..0f8ed3710c66e9e24450a77ba1d86fd9d2a01ea3 100644 (file)
@@ -19,6 +19,16 @@ Required properties:
    providing multiple PM domains (e.g. power controllers), but can be any value
    as specified by device tree binding documentation of particular provider.
 
+Optional properties:
+ - power-domains : A phandle and PM domain specifier as defined by bindings of
+                   the power controller specified by phandle.
+   Some power domains might be powered from another power domain (or have
+   other hardware specific dependencies). For representing such dependency
+   a standard PM domain consumer binding is used. When provided, all domains
+   created by the given provider should be subdomains of the domain
+   specified by this binding. More details about power domain specifier are
+   available in the next section.
+
 Example:
 
        power: power-controller@12340000 {
@@ -30,6 +40,25 @@ Example:
 The node above defines a power controller that is a PM domain provider and
 expects one cell as its phandle argument.
 
+Example 2:
+
+       parent: power-controller@12340000 {
+               compatible = "foo,power-controller";
+               reg = <0x12340000 0x1000>;
+               #power-domain-cells = <1>;
+       };
+
+       child: power-controller@12340000 {
+               compatible = "foo,power-controller";
+               reg = <0x12341000 0x1000>;
+               power-domains = <&parent 0>;
+               #power-domain-cells = <1>;
+       };
+
+The nodes above define two power controllers: 'parent' and 'child'.
+Domains created by the 'child' power controller are subdomains of '0' power
+domain provided by the 'parent' power controller.
+
 ==PM domain consumers==
 
 Required properties:
diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt
new file mode 100644 (file)
index 0000000..91d5ab0
--- /dev/null
@@ -0,0 +1,66 @@
+* UART (Universal Asynchronous Receiver/Transmitter)
+
+Required properties:
+- compatible : one of:
+       - "ns8250"
+       - "ns16450"
+       - "ns16550a"
+       - "ns16550"
+       - "ns16750"
+       - "ns16850"
+       - For Tegra20, must contain "nvidia,tegra20-uart"
+       - For other Tegra, must contain '"nvidia,<chip>-uart",
+         "nvidia,tegra20-uart"' where <chip> is tegra30, tegra114, tegra124,
+         tegra132, or tegra210.
+       - "nxp,lpc3220-uart"
+       - "ralink,rt2880-uart"
+       - "ibm,qpace-nwp-serial"
+       - "altr,16550-FIFO32"
+       - "altr,16550-FIFO64"
+       - "altr,16550-FIFO128"
+       - "fsl,16550-FIFO64"
+       - "fsl,ns16550"
+       - "serial" if the port type is unknown.
+- reg : offset and length of the register set for the device.
+- interrupts : should contain uart interrupt.
+- clock-frequency : the input clock frequency for the UART
+        or
+  clocks phandle to refer to the clk used as per Documentation/devicetree
+  /bindings/clock/clock-bindings.txt
+
+Optional properties:
+- current-speed : the current active speed of the UART.
+- reg-offset : offset to apply to the mapbase from the start of the registers.
+- reg-shift : quantity to shift the register offsets by.
+- reg-io-width : the size (in bytes) of the IO accesses that should be
+  performed on the device.  There are some systems that require 32-bit
+  accesses to the UART (e.g. TI davinci).
+- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
+  RTAS and should not be registered.
+- no-loopback-test: set to indicate that the port does not implements loopback
+  test mode
+- fifo-size: the fifo size of the UART.
+- auto-flow-control: one way to enable automatic flow control support. The
+  driver is allowed to detect support for the capability even without this
+  property.
+
+Note:
+* fsl,ns16550:
+  ------------
+  Freescale DUART is very similar to the PC16552D (and to a
+  pair of NS16550A), albeit with some nonstandard behavior such as
+  erratum A-004737 (relating to incorrect BRK handling).
+
+  Represents a single port that is compatible with the DUART found
+  on many Freescale chips (examples include mpc8349, mpc8548,
+  mpc8641d, p4080 and ls2085a).
+
+Example:
+
+       uart@80230000 {
+               compatible = "ns8250";
+               reg = <0x80230000 0x100>;
+               clock-frequency = <3686400>;
+               interrupts = <10>;
+               reg-shift = <2>;
+       };
diff --git a/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt b/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt
new file mode 100644 (file)
index 0000000..ebcbb62
--- /dev/null
@@ -0,0 +1,19 @@
+ETRAX FS UART
+
+Required properties:
+- compatible : "axis,etraxfs-uart"
+- reg: offset and length of the register set for the device.
+- interrupts: device interrupt
+
+Optional properties:
+- {dtr,dsr,ri,cd}-gpios: specify a GPIO for DTR/DSR/RI/CD
+  line respectively.
+
+Example:
+
+serial@b00260000 {
+       compatible = "axis,etraxfs-uart";
+       reg = <0xb0026000 0x1000>;
+       interrupts = <68>;
+       status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt
deleted file mode 100644 (file)
index 91d5ab0..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-* UART (Universal Asynchronous Receiver/Transmitter)
-
-Required properties:
-- compatible : one of:
-       - "ns8250"
-       - "ns16450"
-       - "ns16550a"
-       - "ns16550"
-       - "ns16750"
-       - "ns16850"
-       - For Tegra20, must contain "nvidia,tegra20-uart"
-       - For other Tegra, must contain '"nvidia,<chip>-uart",
-         "nvidia,tegra20-uart"' where <chip> is tegra30, tegra114, tegra124,
-         tegra132, or tegra210.
-       - "nxp,lpc3220-uart"
-       - "ralink,rt2880-uart"
-       - "ibm,qpace-nwp-serial"
-       - "altr,16550-FIFO32"
-       - "altr,16550-FIFO64"
-       - "altr,16550-FIFO128"
-       - "fsl,16550-FIFO64"
-       - "fsl,ns16550"
-       - "serial" if the port type is unknown.
-- reg : offset and length of the register set for the device.
-- interrupts : should contain uart interrupt.
-- clock-frequency : the input clock frequency for the UART
-        or
-  clocks phandle to refer to the clk used as per Documentation/devicetree
-  /bindings/clock/clock-bindings.txt
-
-Optional properties:
-- current-speed : the current active speed of the UART.
-- reg-offset : offset to apply to the mapbase from the start of the registers.
-- reg-shift : quantity to shift the register offsets by.
-- reg-io-width : the size (in bytes) of the IO accesses that should be
-  performed on the device.  There are some systems that require 32-bit
-  accesses to the UART (e.g. TI davinci).
-- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
-  RTAS and should not be registered.
-- no-loopback-test: set to indicate that the port does not implements loopback
-  test mode
-- fifo-size: the fifo size of the UART.
-- auto-flow-control: one way to enable automatic flow control support. The
-  driver is allowed to detect support for the capability even without this
-  property.
-
-Note:
-* fsl,ns16550:
-  ------------
-  Freescale DUART is very similar to the PC16552D (and to a
-  pair of NS16550A), albeit with some nonstandard behavior such as
-  erratum A-004737 (relating to incorrect BRK handling).
-
-  Represents a single port that is compatible with the DUART found
-  on many Freescale chips (examples include mpc8349, mpc8548,
-  mpc8641d, p4080 and ls2085a).
-
-Example:
-
-       uart@80230000 {
-               compatible = "ns8250";
-               reg = <0x80230000 0x100>;
-               clock-frequency = <3686400>;
-               interrupts = <10>;
-               reg-shift = <2>;
-       };
index 7f76214f728aa6028f133a94d04f183ccb3b1c38..289c40ed747042a70b13f9912dc0b5c443f7827e 100644 (file)
@@ -21,6 +21,18 @@ Optional properties:
 - reg-io-width : the size (in bytes) of the IO accesses that should be
   performed on the device.  If this property is not present then single byte
   accesses are used.
+- dcd-override : Override the DCD modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- dsr-override : Override the DTS modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- cts-override : Override the CTS modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- ri-override : Override the RI modem status signal. This signal will always be
+  reported as inactive instead of being obtained from the modem status register.
+  Define this if your serial port does not use this pin.
 
 Example:
 
@@ -31,6 +43,10 @@ Example:
                interrupts = <10>;
                reg-shift = <2>;
                reg-io-width = <4>;
+               dcd-override;
+               dsr-override;
+               cts-override;
+               ri-override;
        };
 
 Example with one clock:
index b41433386e2fe5a72f752ec816eb0f70011b6555..b623d50004fb016195d865179ce71b378c8fc98c 100644 (file)
@@ -1,7 +1,7 @@
 Ingenic JZ4740 I2S controller
 
 Required properties:
-- compatible : "ingenic,jz4740-i2s"
+- compatible : "ingenic,jz4740-i2s" or "ingenic,jz4780-i2s"
 - reg : I2S registers location and length
 - clocks : AIC and I2S PLL clock specifiers.
 - clock-names: "aic" and "i2s"
diff --git a/Documentation/devicetree/bindings/sound/max98925.txt b/Documentation/devicetree/bindings/sound/max98925.txt
new file mode 100644 (file)
index 0000000..27be63e
--- /dev/null
@@ -0,0 +1,22 @@
+max98925 audio CODEC
+
+This device supports I2C.
+
+Required properties:
+
+  - compatible : "maxim,max98925"
+
+  - vmon-slot-no : slot number used to send voltage information
+
+  - imon-slot-no : slot number used to send current information
+
+  - reg : the I2C address of the device for I2C
+
+Example:
+
+codec: max98925@1a {
+       compatible = "maxim,max98925";
+       vmon-slot-no = <0>;
+       imon-slot-no = <2>;
+       reg = <0x1a>;
+};
index c949abc2992f5fd1d8c2e1fcb2eb5a75521037a6..c3495beba35841773cd1ec0c7d3efe1d952d22c4 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 56742bc70218bfd5d4035732301f1df6c6f4927e..7d44eae7ab0b951d2ea77889cee1c6733978dd0b 100644 (file)
@@ -12,6 +12,9 @@ I. For patch submitters
 
        devicetree@vger.kernel.org
 
+     and Cc: the DT maintainers. Use scripts/get_maintainer.pl to identify
+     all of the DT maintainers.
+
   3) The Documentation/ portion of the patch should come in the series before
      the code implementing the binding.
 
index 389ca1347a771cb049994db077fc38d2d04b7020..fae26d014aaf25c83f499889969e1cb017491f34 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 f90e294d7631f9b538ba3e5e72c2ab1b096a5479..a4d869744f5958f7bd0311868ef3c7b1c3956386 100644 (file)
@@ -26,6 +26,11 @@ Optional properties:
 - atmel,disable : Should be present if you want to disable the watchdog.
 - atmel,idle-halt : Should be present if you want to stop the watchdog when
        entering idle state.
+       CAUTION: This property should be used with care, it actually makes the
+       watchdog not counting when the CPU is in idle state, therefore the
+       watchdog reset time depends on mean CPU usage and will not reset at all
+       if the CPU stop working while it is in idle state, which is probably
+       not what you want.
 - atmel,dbg-halt : Should be present if you want to stop the watchdog when
        entering debug state.
 
index 1b528b2ad809b8418cb352be8755de286b78882f..fcf4d509d1186f728b77e398c438af0850d9511c 100644 (file)
@@ -5,8 +5,8 @@ system.
 
 dlmfs is built with OCFS2 as it requires most of its infrastructure.
 
-Project web page:    http://oss.oracle.com/projects/ocfs2
-Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
+Project web page:    http://ocfs2.wiki.kernel.org
+Tools web page:      https://github.com/markfasheh/ocfs2-tools
 OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
 All code copyright 2005 Oracle except when otherwise noted.
index 28f8c08201e29e0e90e2a489997f7a6b1d78dabb..4c49e5410595c0ee86447ed6312d58315e2e974c 100644 (file)
@@ -8,8 +8,8 @@ also make it attractive for non-clustered use.
 You'll want to install the ocfs2-tools package in order to at least
 get "mount.ocfs2" and "ocfs2_hb_ctl".
 
-Project web page:    http://oss.oracle.com/projects/ocfs2
-Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
+Project web page:    http://ocfs2.wiki.kernel.org
+Tools git tree:      https://github.com/markfasheh/ocfs2-tools
 OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
 All code copyright 2005 Oracle except when otherwise noted.
index a63e5e013a8cddee63b1d3520dd1c2c73e80dc31..92ae734c00c348ab810373e0dc838a92462c932f 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 c587a966413e8597da3241f851db92f6e6df1d81..96705616f5820a6d48d6cfda497c7fcf30917e2a 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 7b4f59c09ee2301d077446f5f9ce9c2b96aa2551..b85d000faeb4067c9ab1ed06690105d459a40a4e 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 2f9c5a5fcb25ff2d91aa196123952b01d0908e34..8afb29a8604a552c9dc1b1794466bf20933dca35 100644 (file)
@@ -40,8 +40,10 @@ but also to IPIs and to some other special-purpose interrupts.
 
 The IRQF_NO_SUSPEND flag is used to indicate that to the IRQ subsystem when
 requesting a special-purpose interrupt.  It causes suspend_device_irqs() to
-leave the corresponding IRQ enabled so as to allow the interrupt to work all
-the time as expected.
+leave the corresponding IRQ enabled so as to allow the interrupt to work as
+expected during the suspend-resume cycle, but does not guarantee that the
+interrupt will wake the system from a suspended state -- for such cases it is
+necessary to use enable_irq_wake().
 
 Note that the IRQF_NO_SUSPEND flag affects the entire IRQ and not just one
 user of it.  Thus, if the IRQ is shared, all of the interrupt handlers installed
@@ -110,8 +112,9 @@ any special interrupt handling logic for it to work.
 IRQF_NO_SUSPEND and enable_irq_wake()
 -------------------------------------
 
-There are no valid reasons to use both enable_irq_wake() and the IRQF_NO_SUSPEND
-flag on the same IRQ.
+There are very few valid reasons to use both enable_irq_wake() and the
+IRQF_NO_SUSPEND flag on the same IRQ, and it is never valid to use both for the
+same device.
 
 First of all, if the IRQ is not shared, the rules for handling IRQF_NO_SUSPEND
 interrupts (interrupt handlers are invoked after suspend_device_irqs()) are
@@ -120,4 +123,13 @@ handlers are not invoked after suspend_device_irqs()).
 
 Second, both enable_irq_wake() and IRQF_NO_SUSPEND apply to entire IRQs and not
 to individual interrupt handlers, so sharing an IRQ between a system wakeup
-interrupt source and an IRQF_NO_SUSPEND interrupt source does not make sense.
+interrupt source and an IRQF_NO_SUSPEND interrupt source does not generally
+make sense.
+
+In rare cases an IRQ can be shared between a wakeup device driver and an
+IRQF_NO_SUSPEND user. In order for this to be safe, the wakeup device driver
+must be able to discern spurious IRQs from genuine wakeup events (signalling
+the latter to the core with pm_system_wakeup()), must use enable_irq_wake() to
+ensure that the IRQ will function as a wakeup source, and must request the IRQ
+with IRQF_COND_SUSPEND to tell the core that it meets these requirements. If
+these requirements are not met, it is not valid to use IRQF_COND_SUSPEND.
index 79a6127863ca8216294f9861d068e31b5a09bd16..3fc1cf50d28e18c0d1706e8b99304bbfb780dcd1 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 ddc5a8cf9a8ac0078f8ca1bc99d9c48f8197214a..3a3c461e0787db9935f3332054c0b8b8a6077084 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 9fab639727c78e5370538afcd6980f167af6fdf6..54430f933b628ca99bdbc1e2bf5dd2570ca0354c 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 4e547296831d62ea673239dcb224c69ee02cd782..52312cb5dbe21490b48e21343ab8f82b7eecfc0e 100644 (file)
@@ -47,9 +47,6 @@ struct thread_struct {
 /* Forward declaration, a strange C thing */
 struct task_struct;
 
-/* Return saved PC of a blocked thread  */
-unsigned long thread_saved_pc(struct task_struct *t);
-
 #define task_pt_regs(p) \
        ((struct pt_regs *)(THREAD_SIZE + (void *)task_stack_page(p)) - 1)
 
@@ -72,18 +69,21 @@ unsigned long thread_saved_pc(struct task_struct *t);
 #define release_segments(mm)        do { } while (0)
 
 #define KSTK_EIP(tsk)   (task_pt_regs(tsk)->ret)
+#define KSTK_ESP(tsk)   (task_pt_regs(tsk)->sp)
 
 /*
  * Where abouts of Task's sp, fp, blink when it was last seen in kernel mode.
  * Look in process.c for details of kernel stack layout
  */
-#define KSTK_ESP(tsk)   (tsk->thread.ksp)
+#define TSK_K_ESP(tsk)         (tsk->thread.ksp)
 
-#define KSTK_REG(tsk, off)     (*((unsigned int *)(KSTK_ESP(tsk) + \
+#define TSK_K_REG(tsk, off)    (*((unsigned int *)(TSK_K_ESP(tsk) + \
                                        sizeof(struct callee_regs) + off)))
 
-#define KSTK_BLINK(tsk) KSTK_REG(tsk, 4)
-#define KSTK_FP(tsk)    KSTK_REG(tsk, 0)
+#define TSK_K_BLINK(tsk)       TSK_K_REG(tsk, 4)
+#define TSK_K_FP(tsk)          TSK_K_REG(tsk, 0)
+
+#define thread_saved_pc(tsk)   TSK_K_BLINK(tsk)
 
 extern void start_thread(struct pt_regs * regs, unsigned long pc,
                         unsigned long usp);
diff --git a/arch/arc/include/asm/stacktrace.h b/arch/arc/include/asm/stacktrace.h
new file mode 100644 (file)
index 0000000..b29b606
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
+ * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_STACKTRACE_H
+#define __ASM_STACKTRACE_H
+
+#include <linux/sched.h>
+
+/**
+ * arc_unwind_core - Unwind the kernel mode stack for an execution context
+ * @tsk:               NULL for current task, specific task otherwise
+ * @regs:              pt_regs used to seed the unwinder {SP, FP, BLINK, PC}
+ *                     If NULL, use pt_regs of @tsk (if !NULL) otherwise
+ *                     use the current values of {SP, FP, BLINK, PC}
+ * @consumer_fn:       Callback invoked for each frame unwound
+ *                     Returns 0 to continue unwinding, -1 to stop
+ * @arg:               Arg to callback
+ *
+ * Returns the address of first function in stack
+ *
+ * Semantics:
+ *  - synchronous unwinding (e.g. dump_stack): @tsk  NULL, @regs  NULL
+ *  - Asynchronous unwinding of sleeping task: @tsk !NULL, @regs  NULL
+ *  - Asynchronous unwinding of intr/excp etc: @tsk !NULL, @regs !NULL
+ */
+notrace noinline unsigned int arc_unwind_core(
+       struct task_struct *tsk, struct pt_regs *regs,
+       int (*consumer_fn) (unsigned int, void *),
+       void *arg);
+
+#endif /* __ASM_STACKTRACE_H */
index fdd89715d2d3783f8a1302513c10a15d138ded91..98c00a2d4dd9a57f1c503ac2ebb6d63a3f1a76b4 100644 (file)
@@ -192,29 +192,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
        return 0;
 }
 
-/*
- * API: expected by schedular Code: If thread is sleeping where is that.
- * What is this good for? it will be always the scheduler or ret_from_fork.
- * So we hard code that anyways.
- */
-unsigned long thread_saved_pc(struct task_struct *t)
-{
-       struct pt_regs *regs = task_pt_regs(t);
-       unsigned long blink = 0;
-
-       /*
-        * If the thread being queried for in not itself calling this, then it
-        * implies it is not executing, which in turn implies it is sleeping,
-        * which in turn implies it got switched OUT by the schedular.
-        * In that case, it's kernel mode blink can reliably retrieved as per
-        * the picture above (right above pt_regs).
-        */
-       if (t != current && t->state != TASK_RUNNING)
-               blink = *((unsigned int *)regs - 1);
-
-       return blink;
-}
-
 int elf_check_arch(const struct elf32_hdr *x)
 {
        unsigned int eflags;
index 114234e83caa25968e08302b5e61f14e152e2d16..edda76fae83f25219bd74c5487a458e29c765373 100644 (file)
@@ -67,7 +67,7 @@ stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,
               sigset_t *set)
 {
        int err;
-       err = __copy_to_user(&(sf->uc.uc_mcontext.regs), regs,
+       err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), regs,
                             sizeof(sf->uc.uc_mcontext.regs.scratch));
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t));
 
@@ -83,7 +83,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
        if (!err)
                set_current_blocked(&set);
 
-       err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs),
+       err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs.scratch),
                                sizeof(sf->uc.uc_mcontext.regs.scratch));
 
        return err;
@@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn)
        /* Don't restart from sigreturn */
        syscall_wont_restart(regs);
 
+       /*
+        * Ensure that sigreturn always returns to user mode (in case the
+        * regs saved on user stack got fudged between save and sigreturn)
+        * Otherwise it is easy to panic the kernel with a custom
+        * signal handler and/or restorer which clobberes the status32/ret
+        * to return to a bogus location in kernel mode.
+        */
+       regs->status32 |= STATUS_U_MASK;
+
        return regs->r0;
 
 badframe:
@@ -229,8 +238,11 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
 
        /*
         * handler returns using sigreturn stub provided already by userpsace
+        * If not, nuke the process right away
         */
-       BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER));
+       if(!(ksig->ka.sa.sa_flags & SA_RESTORER))
+               return 1;
+
        regs->blink = (unsigned long)ksig->ka.sa.sa_restorer;
 
        /* User Stack for signal handler will be above the frame just carved */
@@ -296,12 +308,12 @@ static void
 handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 {
        sigset_t *oldset = sigmask_to_save();
-       int ret;
+       int failed;
 
        /* Set up the stack frame */
-       ret = setup_rt_frame(ksig, oldset, regs);
+       failed = setup_rt_frame(ksig, oldset, regs);
 
-       signal_setup_done(ret, ksig, 0);
+       signal_setup_done(failed, ksig, 0);
 }
 
 void do_signal(struct pt_regs *regs)
index 9ce47cfe23037fa12f463a350819731422aadd9b..92320d6f737cf5149d0968f5da3cd73a47af9848 100644 (file)
@@ -43,6 +43,10 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                                   struct pt_regs *regs,
                                   struct unwind_frame_info *frame_info)
 {
+       /*
+        * synchronous unwinding (e.g. dump_stack)
+        *  - uses current values of SP and friends
+        */
        if (tsk == NULL && regs == NULL) {
                unsigned long fp, sp, blink, ret;
                frame_info->task = current;
@@ -61,12 +65,17 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                frame_info->regs.r63 = ret;
                frame_info->call_frame = 0;
        } else if (regs == NULL) {
+               /*
+                * Asynchronous unwinding of sleeping task
+                *  - Gets SP etc from task's pt_regs (saved bottom of kernel
+                *    mode stack of task)
+                */
 
                frame_info->task = tsk;
 
-               frame_info->regs.r27 = KSTK_FP(tsk);
-               frame_info->regs.r28 = KSTK_ESP(tsk);
-               frame_info->regs.r31 = KSTK_BLINK(tsk);
+               frame_info->regs.r27 = TSK_K_FP(tsk);
+               frame_info->regs.r28 = TSK_K_ESP(tsk);
+               frame_info->regs.r31 = TSK_K_BLINK(tsk);
                frame_info->regs.r63 = (unsigned int)__switch_to;
 
                /* In the prologue of __switch_to, first FP is saved on stack
@@ -83,6 +92,10 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                frame_info->call_frame = 0;
 
        } else {
+               /*
+                * Asynchronous unwinding of intr/exception
+                *  - Just uses the pt_regs passed
+                */
                frame_info->task = tsk;
 
                frame_info->regs.r27 = regs->fp;
@@ -95,7 +108,7 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
 
 #endif
 
-static noinline unsigned int
+notrace noinline unsigned int
 arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
                int (*consumer_fn) (unsigned int, void *), void *arg)
 {
index 7ff5b5c183bb026716295c13f7b123de1d67a96f..74db59b6f39269f072ce606700375ae14ab9ec8c 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/perf_event.h>
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
 #include <asm/disasm.h>
@@ -253,6 +254,7 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs,
                }
        }
 
+       perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, address);
        return 0;
 
 fault:
index 563cb27e37f55f3f99badc9b99e64aca6ee397b7..6a2e006cbcce1f1cd69866e0f0f9f94463d73dcb 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
 #include <linux/kdebug.h>
+#include <linux/perf_event.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu.h>
 
@@ -139,13 +140,20 @@ good_area:
                        return;
        }
 
+       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+
        if (likely(!(fault & VM_FAULT_ERROR))) {
                if (flags & FAULT_FLAG_ALLOW_RETRY) {
                        /* To avoid updating stats twice for retry case */
-                       if (fault & VM_FAULT_MAJOR)
+                       if (fault & VM_FAULT_MAJOR) {
                                tsk->maj_flt++;
-                       else
+                               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+                                             regs, address);
+                       } else {
                                tsk->min_flt++;
+                               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+                                             regs, address);
+                       }
 
                        if (fault & VM_FAULT_RETRY) {
                                flags &= ~FAULT_FLAG_ALLOW_RETRY;
index 9f1f09a2bc9bf28894777c08d6968d7faeba55a6..cf4c0c99aa253f3f69ecc08a07f0c5a695e63640 100644 (file)
@@ -619,6 +619,7 @@ config ARCH_PXA
        select GENERIC_CLOCKEVENTS
        select GPIO_PXA
        select HAVE_IDE
+       select IRQ_DOMAIN
        select MULTI_IRQ_HANDLER
        select PLAT_PXA
        select SPARSE_IRQ
index 7f99cd652203ce5705b22f5f0fc24f0574a82840..eb7bb511f853d975d67c0ee26c1167b2d5054279 100644 (file)
@@ -150,6 +150,7 @@ machine-$(CONFIG_ARCH_BERLIN)               += berlin
 machine-$(CONFIG_ARCH_CLPS711X)                += clps711x
 machine-$(CONFIG_ARCH_CNS3XXX)         += cns3xxx
 machine-$(CONFIG_ARCH_DAVINCI)         += davinci
+machine-$(CONFIG_ARCH_DIGICOLOR)       += digicolor
 machine-$(CONFIG_ARCH_DOVE)            += dove
 machine-$(CONFIG_ARCH_EBSA110)         += ebsa110
 machine-$(CONFIG_ARCH_EFM32)           += efm32
index 6cc25ed912eeff57fc9bd06cc390c6ece3e56b14..c3255e0c90aa829fc792f02d1265d413f3c6e624 100644 (file)
 
 &usb0 {
        status = "okay";
+       dr_mode = "peripheral";
 };
 
 &usb1 {
        cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
        cd-inverted;
 };
+
+&aes {
+       status = "okay";
+};
+
+&sham {
+       status = "okay";
+};
index 83d40f7655e52503d76537a4ceca1c76e3023e97..6b849372042419e21ca67f142c53f62618e5191d 100644 (file)
 &mmc1 {
        vmmc-supply = <&ldo3_reg>;
 };
-
-&sham {
-       status = "okay";
-};
-
-&aes {
-       status = "okay";
-};
index 7266a00aab2ea515397a9046942749cb291eb6d4..5c5667a3624dee614047e6b63efde568c063f431 100644 (file)
        dual_emac_res_vlan = <3>;
 };
 
+&phy_sel {
+       rmii-clock-ext;
+};
+
 &mac {
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&cpsw_default>;
index 712edce7d6fb12904f7063d38e57e36ab051346a..071b56aa0c7e05fd18201b25ba75836edb9aed5e 100644 (file)
@@ -99,7 +99,7 @@
        ehrpwm0_tbclk: ehrpwm0_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <0>;
                reg = <0x0664>;
        };
        ehrpwm1_tbclk: ehrpwm1_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <1>;
                reg = <0x0664>;
        };
        ehrpwm2_tbclk: ehrpwm2_tbclk@44e10664 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <2>;
                reg = <0x0664>;
        };
index f9a17e2ca8cb068dfa63034d43a1077fb0a606bb..0198f5a62b96cd8b8569d4ae5d6dfd2938fcd580 100644 (file)
                >;
        };
 
-       i2c1_pins_default: i2c1_pins_default {
-               pinctrl-single,pins = <
-                       0x15c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_cs0.i2c1_scl */
-                       0x158 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_d1.i2c1_sda */
-               >;
-       };
-
-       i2c1_pins_sleep: i2c1_pins_sleep {
-               pinctrl-single,pins = <
-                       0x15c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_cs0.i2c1_scl */
-                       0x158 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_d1.i2c1_sda */
-               >;
-       };
-
        mmc1_pins_default: pinmux_mmc1_pins_default {
                pinctrl-single,pins = <
                        0x100 (PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
        status = "okay";
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&i2c0_pins_default>;
-       pinctrl-1 = <&i2c0_pins_default>;
+       pinctrl-1 = <&i2c0_pins_sleep>;
        clock-frequency = <400000>;
 
        at24@50 {
                pagesize = <64>;
                reg = <0x50>;
        };
-};
-
-&i2c1 {
-       status = "okay";
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&i2c1_pins_default>;
-       pinctrl-1 = <&i2c1_pins_default>;
-       clock-frequency = <400000>;
 
        tps: tps62362@60 {
                compatible = "ti,tps62362";
+               reg = <0x60>;
                regulator-name = "VDD_MPU";
                regulator-min-microvolt = <950000>;
                regulator-max-microvolt = <1330000>;
index c7dc9dab93a45eaf779497071cb9968027f5e163..cfb49686ab6af02ba7086e344869ee9ad457a2aa 100644 (file)
        ehrpwm0_tbclk: ehrpwm0_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <0>;
                reg = <0x0664>;
        };
        ehrpwm1_tbclk: ehrpwm1_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <1>;
                reg = <0x0664>;
        };
        ehrpwm2_tbclk: ehrpwm2_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <2>;
                reg = <0x0664>;
        };
        ehrpwm3_tbclk: ehrpwm3_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <4>;
                reg = <0x0664>;
        };
        ehrpwm4_tbclk: ehrpwm4_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <5>;
                reg = <0x0664>;
        };
        ehrpwm5_tbclk: ehrpwm5_tbclk {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
-               clocks = <&dpll_per_m2_ck>;
+               clocks = <&l4ls_gclk>;
                ti,bit-shift = <6>;
                reg = <0x0664>;
        };
index 03750af3b49a41493035217c34c16984343b226c..6463f9ef2b548208bda288a78a07ab3353aa2220 100644 (file)
        pinctrl-0 = <&usb1_pins>;
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb2 {
        dr_mode = "peripheral";
 };
index fff0ee69aab495361898b503268fd300a02832c1..e7f0a4ae271c6a53244c3a3b0f6204cae45d6b0b 100644 (file)
 
                                        pinctrl_usart3_rts: usart3_rts-0 {
                                                atmel,pins =
-                                                       <AT91_PIOB 8 AT91_PERIPH_B AT91_PINCTRL_NONE>;  /* PC8 periph B */
+                                                       <AT91_PIOC 8 AT91_PERIPH_B AT91_PINCTRL_NONE>;
                                        };
 
                                        pinctrl_usart3_cts: usart3_cts-0 {
                                                atmel,pins =
-                                                       <AT91_PIOB 10 AT91_PERIPH_B AT91_PINCTRL_NONE>; /* PC10 periph B */
+                                                       <AT91_PIOC 10 AT91_PERIPH_B AT91_PINCTRL_NONE>;
                                        };
                                };
 
                        };
 
                        usb1: gadget@fffa4000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9260-udc";
                                reg = <0xfffa4000 0x4000>;
                                interrupts = <10 IRQ_TYPE_LEVEL_HIGH 2>;
                                clocks = <&udc_clk>, <&udpck>;
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index e247b0b5fdab2fe1cb41e57fd51450ae723256dd..d55fdf2487ef53f7a3c68cded4e78fe42039f538 100644 (file)
                        };
 
                        usb1: gadget@fffa4000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9261-udc";
                                reg = <0xfffa4000 0x4000>;
                                interrupts = <10 IRQ_TYPE_LEVEL_HIGH 2>;
-                               clocks = <&usb>, <&udc_clk>, <&udpck>;
-                               clock-names = "usb_clk", "udc_clk", "udpck";
+                               clocks = <&udc_clk>, <&udpck>;
+                               clock-names = "pclk", "hclk";
+                               atmel,matrix = <&matrix>;
                                status = "disabled";
                        };
 
                        };
 
                        matrix: matrix@ffffee00 {
-                               compatible = "atmel,at91sam9260-bus-matrix";
+                               compatible = "atmel,at91sam9260-bus-matrix", "syscon";
                                reg = <0xffffee00 0x200>;
                        };
 
index 1f67bb4c144eef2489891b63b64edda96402f100..fce301c4e9d6e22aeb37d3a2a4fe83bf6634ad78 100644 (file)
@@ -69,7 +69,7 @@
 
        sram1: sram@00500000 {
                compatible = "mmio-sram";
-               reg = <0x00300000 0x4000>;
+               reg = <0x00500000 0x4000>;
        };
 
        ahb {
                        };
 
                        usb1: gadget@fff78000 {
-                               compatible = "atmel,at91rm9200-udc";
+                               compatible = "atmel,at91sam9263-udc";
                                reg = <0xfff78000 0x4000>;
                                interrupts = <24 IRQ_TYPE_LEVEL_HIGH 2>;
                                clocks = <&udc_clk>, <&udpck>;
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index ee80aa9c0759c17f178965181fb28f2a562f6b13..488af63d5174c7e9dc0eb29319ccb35eebd8fc7c 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00800000 0x100000>;
                        interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "hclk", "uhpck";
                        status = "disabled";
                };
index c2666a7cb5b19b547d31f11d58d5af1c13d36acb..0c53a375ba99d214c1c0b5eabd85e77ec0cc72e6 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index 818dabdd8c0e08e3089092f27117c1927bc6122f..d221179d0f1aad8aaccde552f74962a3009c6274 100644 (file)
                                reg = <0x00500000 0x80000
                                       0xf803c000 0x400>;
                                interrupts = <23 IRQ_TYPE_LEVEL_HIGH 0>;
-                               clocks = <&usb>, <&udphs_clk>;
+                               clocks = <&utmi>, <&udphs_clk>;
                                clock-names = "hclk", "pclk";
                                status = "disabled";
 
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00700000 0x100000>;
                        interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
index 857d0289ad4d7c9ed81268a2d2a20c923b2177a0..afe678f6d2e950308b74e403d26a3cc326c2b760 100644 (file)
                        DM816X_IOPAD(0x0aac, PIN_INPUT | MUX_MODE0)     /* SPI_D1 */
                >;
        };
+
+       mmc_pins: pinmux_mmc_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0a70, MUX_MODE0)                 /* SD_POW */
+                       DM816X_IOPAD(0x0a74, MUX_MODE0)                 /* SD_CLK */
+                       DM816X_IOPAD(0x0a78, MUX_MODE0)                 /* SD_CMD */
+                       DM816X_IOPAD(0x0a7C, MUX_MODE0)                 /* SD_DAT0 */
+                       DM816X_IOPAD(0x0a80, MUX_MODE0)                 /* SD_DAT1 */
+                       DM816X_IOPAD(0x0a84, MUX_MODE0)                 /* SD_DAT2 */
+                       DM816X_IOPAD(0x0a88, MUX_MODE0)                 /* SD_DAT2 */
+                       DM816X_IOPAD(0x0a8c, MUX_MODE2)                 /* GP1[7] */
+                       DM816X_IOPAD(0x0a90, MUX_MODE2)                 /* GP1[8] */
+               >;
+       };
+
+       usb0_pins: pinmux_usb0_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0d00, MUX_MODE0)                 /* USB0_DRVVBUS */
+               >;
+       };
+
+       usb1_pins: pinmux_usb0_pins {
+               pinctrl-single,pins = <
+                       DM816X_IOPAD(0x0d04, MUX_MODE0)                 /* USB1_DRVVBUS */
+               >;
+       };
 };
 
 &i2c1 {
 };
 
 &mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc_pins>;
        vmmc-supply = <&vmmcsd_fixed>;
+       bus-width = <4>;
+       cd-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
+};
+
+/* At least dm8168-evm rev c won't support multipoint, later may */
+&usb0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb0_pins>;
+       mentor,multipoint = <0>;
+};
+
+&usb1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb1_pins>;
+       mentor,multipoint = <0>;
 };
index d98d0f7de380d95d956aa6826dd626c53d500be7..f35715bc69922591577299730ecf1a105c6642de 100644 (file)
 
                        /* Device Configuration Registers */
                        scm_conf: syscon@600 {
-                               compatible = "syscon";
+                               compatible = "syscon", "simple-bus";
                                reg = <0x600 0x110>;
                                #address-cells = <1>;
                                #size-cells = <1>;
+                               ranges = <0 0x600 0x110>;
+
+                               usb_phy0: usb-phy@20 {
+                                       compatible = "ti,dm8168-usb-phy";
+                                       reg = <0x20 0x8>;
+                                       reg-names = "phy";
+                                       clocks = <&main_fapll 6>;
+                                       clock-names = "refclk";
+                                       #phy-cells = <0>;
+                                       syscon = <&scm_conf>;
+                               };
+
+                               usb_phy1: usb-phy@28 {
+                                       compatible = "ti,dm8168-usb-phy";
+                                       reg = <0x28 0x8>;
+                                       reg-names = "phy";
+                                       clocks = <&main_fapll 6>;
+                                       clock-names = "refclk";
+                                       #phy-cells = <0>;
+                                       syscon = <&scm_conf>;
+                               };
                        };
 
                        scrm_clocks: clocks {
                };
 
                gpio1: gpio@48032000 {
-                       compatible = "ti,omap3-gpio";
+                       compatible = "ti,omap4-gpio";
                        ti,hwmods = "gpio1";
+                       ti,gpio-always-on;
                        reg = <0x48032000 0x1000>;
-                       interrupts = <97>;
+                       interrupts = <96>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                gpio2: gpio@4804c000 {
-                       compatible = "ti,omap3-gpio";
+                       compatible = "ti,omap4-gpio";
                        ti,hwmods = "gpio2";
+                       ti,gpio-always-on;
                        reg = <0x4804c000 0x1000>;
-                       interrupts = <99>;
+                       interrupts = <98>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                gpmc: gpmc@50000000 {
                                reg-names = "mc", "control";
                                interrupts = <18>;
                                interrupt-names = "mc";
-                               dr_mode = "otg";
+                               dr_mode = "host";
+                               interface-type = <0>;
+                               phys = <&usb_phy0>;
+                               phy-names = "usb2-phy";
                                mentor,multipoint = <1>;
                                mentor,num-eps = <16>;
                                mentor,ram-bits = <12>;
 
                        usb1: usb@47401800 {
                                compatible = "ti,musb-am33xx";
-                               status = "disabled";
                                reg = <0x47401c00 0x400
                                       0x47401800 0x200>;
                                reg-names = "mc", "control";
                                interrupts = <19>;
                                interrupt-names = "mc";
-                               dr_mode = "otg";
+                               dr_mode = "host";
+                               interface-type = <0>;
+                               phys = <&usb_phy1>;
+                               phy-names = "usb2-phy";
                                mentor,multipoint = <1>;
                                mentor,num-eps = <16>;
                                mentor,ram-bits = <12>;
index 746cddb1b8f538e1d1fed717b077998f4a46adc8..7563d7ce01bbc74ed71fab8cd07a578060325500 100644 (file)
 
        dcan1_pins_default: dcan1_pins_default {
                pinctrl-single,pins = <
-                       0x3d0   (PIN_OUTPUT | MUX_MODE0) /* dcan1_tx */
-                       0x3d4   (MUX_MODE15)            /* dcan1_rx.off */
-                       0x418   (PULL_DIS | MUX_MODE1) /* wakeup0.dcan1_rx */
+                       0x3d0   (PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
+                       0x418   (PULL_UP | MUX_MODE1) /* wakeup0.dcan1_rx */
                >;
        };
 
        dcan1_pins_sleep: dcan1_pins_sleep {
                pinctrl-single,pins = <
-                       0x3d0   (MUX_MODE15)    /* dcan1_tx.off */
-                       0x3d4   (MUX_MODE15)    /* dcan1_rx.off */
-                       0x418   (MUX_MODE15)    /* wakeup0.off */
+                       0x3d0   (MUX_MODE15 | PULL_UP)  /* dcan1_tx.off */
+                       0x418   (MUX_MODE15 | PULL_UP)  /* wakeup0.off */
                >;
        };
 };
        };
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb1 {
        dr_mode = "peripheral";
        pinctrl-names = "default";
index 5827fedafd43d58a00169a4186cbb595d6f11234..c4659a979c41387558f8ea660d119568645acbcb 100644 (file)
                                     <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4ae10000 {
                                      <0x4A096800 0x40>; /* pll_ctrl */
                                reg-names = "phy_rx", "phy_tx", "pll_ctrl";
                                ctrl-module = <&omap_control_sata>;
-                               clocks = <&sys_clkin1>;
-                               clock-names = "sysclk";
+                               clocks = <&sys_clkin1>, <&sata_ref_clk>;
+                               clock-names = "sysclk", "refclk";
                                #phy-cells = <0>;
                        };
 
                                              "wkupclk", "refclk",
                                              "div-clk", "phy-div";
                                #phy-cells = <0>;
-                               ti,hwmods = "pcie1-phy";
                        };
 
                        pcie2_phy: pciephy@4a095000 {
                                              "wkupclk", "refclk",
                                              "div-clk", "phy-div";
                                #phy-cells = <0>;
-                               ti,hwmods = "pcie2-phy";
                                status = "disabled";
                        };
                };
index 4d87117136108873d2410ffaa68010652fd2e356..40ed539ce4743a0f3eccc319e4a4c6be09472363 100644 (file)
 
        dcan1_pins_default: dcan1_pins_default {
                pinctrl-single,pins = <
-                       0x3d0   (PIN_OUTPUT | MUX_MODE0) /* dcan1_tx */
-                       0x3d4   (MUX_MODE15)            /* dcan1_rx.off */
-                       0x418   (PULL_DIS | MUX_MODE1) /* wakeup0.dcan1_rx */
+                       0x3d0   (PIN_OUTPUT_PULLUP | MUX_MODE0) /* dcan1_tx */
+                       0x418   (PULL_UP | MUX_MODE1)   /* wakeup0.dcan1_rx */
                >;
        };
 
        dcan1_pins_sleep: dcan1_pins_sleep {
                pinctrl-single,pins = <
-                       0x3d0   (MUX_MODE15)    /* dcan1_tx.off */
-                       0x3d4   (MUX_MODE15)    /* dcan1_rx.off */
-                       0x418   (MUX_MODE15)    /* wakeup0.off */
+                       0x3d0   (MUX_MODE15 | PULL_UP)  /* dcan1_tx.off */
+                       0x418   (MUX_MODE15 | PULL_UP)  /* wakeup0.off */
                >;
        };
 
        phy-supply = <&ldo4_reg>;
 };
 
-&omap_dwc3_1 {
-       extcon = <&extcon_usb1>;
-};
-
-&omap_dwc3_2 {
-       extcon = <&extcon_usb2>;
-};
-
 &usb1 {
        dr_mode = "peripheral";
        pinctrl-names = "default";
index 4bdcbd61ce47eac73d287448b2163426d67c7305..99b09a44e2694129ece5426f8df2227719255a37 100644 (file)
                ti,invert-autoidle-bit;
        };
 
+       dpll_core_byp_mux: dpll_core_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x012c>;
+       };
+
        dpll_core_ck: dpll_core_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-core-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_core_byp_mux>;
                reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_dsp_byp_mux: dpll_dsp_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x0240>;
+       };
+
        dpll_dsp_ck: dpll_dsp_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_dsp_byp_mux>;
                reg = <0x0234>, <0x0238>, <0x0240>, <0x023c>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_iva_byp_mux: dpll_iva_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x01ac>;
+       };
+
        dpll_iva_ck: dpll_iva_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_iva_byp_mux>;
                reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_gpu_byp_mux: dpll_gpu_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x02e4>;
+       };
+
        dpll_gpu_ck: dpll_gpu_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_gpu_byp_mux>;
                reg = <0x02d8>, <0x02dc>, <0x02e4>, <0x02e0>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_ddr_byp_mux: dpll_ddr_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x021c>;
+       };
+
        dpll_ddr_ck: dpll_ddr_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_ddr_byp_mux>;
                reg = <0x0210>, <0x0214>, <0x021c>, <0x0218>;
        };
 
                ti,invert-autoidle-bit;
        };
 
+       dpll_gmac_byp_mux: dpll_gmac_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x02b4>;
+       };
+
        dpll_gmac_ck: dpll_gmac_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin1>, <&dpll_gmac_byp_mux>;
                reg = <0x02a8>, <0x02ac>, <0x02b4>, <0x02b0>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_eve_byp_mux: dpll_eve_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x0290>;
+       };
+
        dpll_eve_ck: dpll_eve_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_eve_byp_mux>;
                reg = <0x0284>, <0x0288>, <0x0290>, <0x028c>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_per_byp_mux: dpll_per_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x014c>;
+       };
+
        dpll_per_ck: dpll_per_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_per_byp_mux>;
                reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_usb_byp_mux: dpll_usb_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x018c>;
+       };
+
        dpll_usb_ck: dpll_usb_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-j-type-clock";
-               clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>;
+               clocks = <&sys_clkin1>, <&dpll_usb_byp_mux>;
                reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
        };
 
index 277b48b0b6f9cd155737550d0586e9d720cf75f4..ac6b0ae42caff5f9ad7d14307f2421ddbf35c689 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "skeleton.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 #include <dt-bindings/clock/exynos3250.h>
 
 / {
                        interrupts = <0 216 0>;
                        clocks = <&cmu CLK_TMU_APBIF>;
                        clock-names = "tmu_apbif";
+                       #include "exynos4412-tmu-sensor-conf.dtsi"
                        status = "disabled";
                };
 
diff --git a/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi b/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi
new file mode 100644 (file)
index 0000000..735cb2f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Device tree sources for Exynos4 thermal zone
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <dt-bindings/thermal/thermal.h>
+
+/ {
+thermal-zones {
+       cpu_thermal: cpu-thermal {
+               thermal-sensors = <&tmu 0>;
+               polling-delay-passive = <0>;
+               polling-delay = <0>;
+               trips {
+                       cpu_alert0: cpu-alert-0 {
+                               temperature = <70000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_alert1: cpu-alert-1 {
+                               temperature = <95000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_alert2: cpu-alert-2 {
+                               temperature = <110000>; /* millicelsius */
+                               hysteresis = <10000>; /* millicelsius */
+                               type = "active";
+                       };
+                       cpu_crit0: cpu-crit-0 {
+                               temperature = <120000>; /* millicelsius */
+                               hysteresis = <0>; /* millicelsius */
+                               type = "critical";
+                       };
+               };
+               cooling-maps {
+                       map0 {
+                               trip = <&cpu_alert0>;
+                       };
+                       map1 {
+                               trip = <&cpu_alert1>;
+                       };
+               };
+       };
+};
+};
index 76173cacd4501fdd5af0ff061cf6f93e3bd922df..77ea547768f4fa24965ce945b6a7ea2adc12ba60 100644 (file)
@@ -38,6 +38,7 @@
                i2c5 = &i2c_5;
                i2c6 = &i2c_6;
                i2c7 = &i2c_7;
+               i2c8 = &i2c_8;
                csis0 = &csis_0;
                csis1 = &csis_1;
                fimc0 = &fimc_0;
                compatible = "samsung,exynos4210-pd";
                reg = <0x10023C20 0x20>;
                #power-domain-cells = <0>;
+               power-domains = <&pd_lcd0>;
        };
 
        pd_cam: cam-power-domain@10023C00 {
                status = "disabled";
        };
 
+       i2c_8: i2c@138E0000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "samsung,s3c2440-hdmiphy-i2c";
+               reg = <0x138E0000 0x100>;
+               interrupts = <0 93 0>;
+               clocks = <&clock CLK_I2C_HDMI>;
+               clock-names = "i2c";
+               status = "disabled";
+
+               hdmi_i2c_phy: hdmiphy@38 {
+                       compatible = "exynos4210-hdmiphy";
+                       reg = <0x38>;
+               };
+       };
+
        spi_0: spi@13920000 {
                compatible = "samsung,exynos4210-spi";
                reg = <0x13920000 0x100>;
                status = "disabled";
        };
 
+       tmu: tmu@100C0000 {
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       hdmi: hdmi@12D00000 {
+               compatible = "samsung,exynos4210-hdmi";
+               reg = <0x12D00000 0x70000>;
+               interrupts = <0 92 0>;
+               clock-names = "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy",
+                       "mout_hdmi";
+               clocks = <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>,
+                       <&clock CLK_SCLK_PIXEL>, <&clock CLK_SCLK_HDMIPHY>,
+                       <&clock CLK_MOUT_HDMI>;
+               phy = <&hdmi_i2c_phy>;
+               power-domains = <&pd_tv>;
+               samsung,syscon-phandle = <&pmu_system_controller>;
+               status = "disabled";
+       };
+
+       mixer: mixer@12C10000 {
+               compatible = "samsung,exynos4210-mixer";
+               interrupts = <0 91 0>;
+               reg = <0x12C10000 0x2100>, <0x12c00000 0x300>;
+               power-domains = <&pd_tv>;
+               status = "disabled";
+       };
+
        ppmu_dmc0: ppmu_dmc0@106a0000 {
                compatible = "samsung,exynos-ppmu";
                reg = <0x106a0000 0x2000>;
index 3d6652a4b6cbafad4a935ee82430c0b998e8590e..32c5fd8f6269d9c5932de0d715e7763f99541057 100644 (file)
                status = "okay";
        };
 
+       tmu@100C0000 {
+               status = "okay";
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 2 2>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 4 4>;
+                              };
+                      };
+               };
+       };
+
        camera {
                pinctrl-names = "default";
                pinctrl-0 = <>;
index b57e6b82ea203b521399fc13f56f3e3a99c10c17..d4f2b11319dd10d4d7b79fa295d55e63baccff9c 100644 (file)
                        assigned-clock-rates = <0>, <160000000>;
                };
        };
+
+       hdmi_en: voltage-regulator-hdmi-5v {
+               compatible = "regulator-fixed";
+               regulator-name = "HDMI_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpe0 1 0>;
+               enable-active-high;
+       };
+
+       hdmi_ddc: i2c-ddc {
+               compatible = "i2c-gpio";
+               gpios = <&gpe4 2 0 &gpe4 3 0>;
+               i2c-gpio,delay-us = <100>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pinctrl-0 = <&i2c_ddc_bus>;
+               pinctrl-names = "default";
+               status = "okay";
+       };
+
+       mixer@12C10000 {
+               status = "okay";
+       };
+
+       hdmi@12D00000 {
+               hpd-gpio = <&gpx3 7 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmi_hpd>;
+               hdmi-en-supply = <&hdmi_en>;
+               vdd-supply = <&ldo3_reg>;
+               vdd_osc-supply = <&ldo4_reg>;
+               vdd_pll-supply = <&ldo3_reg>;
+               ddc = <&hdmi_ddc>;
+               status = "okay";
+       };
+
+       i2c@138E0000 {
+               status = "okay";
+       };
+};
+
+&pinctrl_1 {
+       hdmi_hpd: hdmi-hpd {
+               samsung,pins = "gpx3-7";
+               samsung,pin-pud = <0>;
+       };
+};
+
+&pinctrl_0 {
+       i2c_ddc_bus: i2c-ddc-bus {
+               samsung,pins = "gpe4-2", "gpe4-3";
+               samsung,pin-function = <2>;
+               samsung,pin-pud = <3>;
+               samsung,pin-drv = <0>;
+       };
 };
 
 &mdma1 {
index 67c832c9dcf140d6203d742810a374aff867ef69..be89f83f70e7750577441c7400567a57c89ec9cb 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "exynos4.dtsi"
 #include "exynos4210-pinctrl.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 
 / {
        compatible = "samsung,exynos4210", "samsung,exynos4";
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@900 {
+               cpu0: cpu@900 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0x900>;
+                       cooling-min-level = <4>;
+                       cooling-max-level = <2>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@901 {
                reg = <0x03860000 0x1000>;
        };
 
-       tmu@100C0000 {
+       tmu: tmu@100C0000 {
                compatible = "samsung,exynos4210-tmu";
                interrupt-parent = <&combiner>;
                reg = <0x100C0000 0x100>;
                interrupts = <2 4>;
                clocks = <&clock CLK_TMU_APBIF>;
                clock-names = "tmu_apbif";
+               samsung,tmu_gain = <15>;
+               samsung,tmu_reference_voltage = <7>;
                status = "disabled";
        };
 
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&tmu 0>;
+
+                       trips {
+                             cpu_alert0: cpu-alert-0 {
+                                     temperature = <85000>; /* millicelsius */
+                             };
+                             cpu_alert1: cpu-alert-1 {
+                                     temperature = <100000>; /* millicelsius */
+                             };
+                             cpu_alert2: cpu-alert-2 {
+                                     temperature = <110000>; /* millicelsius */
+                             };
+                       };
+               };
+       };
+
        g2d@12800000 {
                compatible = "samsung,s5pv210-g2d";
                reg = <0x12800000 0x1000>;
                };
        };
 
+       mixer: mixer@12C10000 {
+               clock-names = "mixer", "hdmi", "sclk_hdmi", "vp", "mout_mixer",
+                       "sclk_mixer";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                       <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>,
+                       <&clock CLK_MOUT_MIXER>, <&clock CLK_SCLK_MIXER>;
+       };
+
        ppmu_lcd1: ppmu_lcd1@12240000 {
                compatible = "samsung,exynos-ppmu";
                reg = <0x12240000 0x2000>;
index dd0a43ec56da905d64fc02f596b70d0ce92e67f3..5be03288f1ee6157cf35849c256743c9ff86b70d 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@A00 {
+               cpu0: cpu@A00 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0xA00>;
+                       cooling-min-level = <13>;
+                       cooling-max-level = <7>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@A01 {
index de80b5bba20454b3e504fd26228d581bcb725190..adb4f6a97a1d5b19d67d486e7d36dd386884d1fd 100644 (file)
                                        regulator-always-on;
                                };
 
+                               ldo8_reg: ldo@8 {
+                                       regulator-compatible = "LDO8";
+                                       regulator-name = "VDD10_HDMI_1.0V";
+                                       regulator-min-microvolt = <1000000>;
+                                       regulator-max-microvolt = <1000000>;
+                               };
+
+                               ldo10_reg: ldo@10 {
+                                       regulator-compatible = "LDO10";
+                                       regulator-name = "VDDQ_MIPIHSI_1.8V";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                               };
+
                                ldo11_reg: LDO11 {
                                        regulator-name = "VDD18_ABB1_1.8V";
                                        regulator-min-microvolt = <1800000>;
        ehci: ehci@12580000 {
                status = "okay";
        };
+
+       tmu@100C0000 {
+               vtmu-supply = <&ldo10_reg>;
+               status = "okay";
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 7 7>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 13 13>;
+                              };
+                      };
+               };
+       };
+
+       mixer: mixer@12C10000 {
+               status = "okay";
+       };
+
+       hdmi@12D00000 {
+               hpd-gpio = <&gpx3 7 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmi_hpd>;
+               vdd-supply = <&ldo8_reg>;
+               vdd_osc-supply = <&ldo10_reg>;
+               vdd_pll-supply = <&ldo8_reg>;
+               ddc = <&hdmi_ddc>;
+               status = "okay";
+       };
+
+       hdmi_ddc: i2c@13880000 {
+               status = "okay";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c2_bus>;
+       };
+
+       i2c@138E0000 {
+               status = "okay";
+       };
 };
 
 &pinctrl_1 {
                samsung,pin-pud = <0>;
                samsung,pin-drv = <0>;
        };
+
+       hdmi_hpd: hdmi-hpd {
+               samsung,pins = "gpx3-7";
+               samsung,pin-pud = <1>;
+       };
 };
diff --git a/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi
new file mode 100644 (file)
index 0000000..e3f7934
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Device tree sources for Exynos4412 TMU sensor configuration
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <dt-bindings/thermal/thermal_exynos.h>
+
+#thermal-sensor-cells = <0>;
+samsung,tmu_gain = <8>;
+samsung,tmu_reference_voltage = <16>;
+samsung,tmu_noise_cancel_mode = <4>;
+samsung,tmu_efuse_value = <55>;
+samsung,tmu_min_efuse_value = <40>;
+samsung,tmu_max_efuse_value = <100>;
+samsung,tmu_first_point_trim = <25>;
+samsung,tmu_second_point_trim = <85>;
+samsung,tmu_default_temp_offset = <50>;
+samsung,tmu_cal_type = <TYPE_ONE_POINT_TRIMMING>;
index 21f7480835868396061bc8216833eae37398398a..173ffa479ad3cb03eb6e6742663fafaccacf9d53 100644 (file)
                pulldown-ohm = <100000>; /* 100K */
                io-channels = <&adc 2>;  /* Battery temperature */
        };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 7 7>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 13 13>;
+                              };
+                      };
+               };
+       };
 };
 
 &pmu_system_controller {
index 0f6ec93bb1d8a243d511dac4e2e42f6a794e9015..68ad43b391ae6122c3783b443cf23b5ccb7a2d04 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@A00 {
+               cpu0: cpu@A00 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0xA00>;
+                       cooling-min-level = <13>;
+                       cooling-max-level = <7>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
 
                cpu@A01 {
index f5e0ae780d6ce8dd25622abed741b03416570f03..6a6abe14fd9b59eed66e033ef43b970c6d4ce256 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "exynos4.dtsi"
 #include "exynos4x12-pinctrl.dtsi"
+#include "exynos4-cpu-thermal.dtsi"
 
 / {
        aliases {
                clock-names = "tmu_apbif";
                status = "disabled";
        };
+
+       hdmi: hdmi@12D00000 {
+               compatible = "samsung,exynos4212-hdmi";
+       };
+
+       mixer: mixer@12C10000 {
+               compatible = "samsung,exynos4212-mixer";
+               clock-names = "mixer", "hdmi", "sclk_hdmi", "vp";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>;
+       };
 };
index 9bb1b0b738f53d2e544baa582faeec5841b16783..adbde1adad95ddf0bde124e25b2b16ac41dba83b 100644 (file)
@@ -20,7 +20,7 @@
 #include <dt-bindings/clock/exynos5250.h>
 #include "exynos5.dtsi"
 #include "exynos5250-pinctrl.dtsi"
-
+#include "exynos4-cpu-thermal.dtsi"
 #include <dt-bindings/clock/exynos-audss-clk.h>
 
 / {
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@0 {
+               cpu0: cpu@0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0>;
                        clock-frequency = <1700000000>;
+                       cooling-min-level = <15>;
+                       cooling-max-level = <9>;
+                       #cooling-cells = <2>; /* min followed by max */
                };
                cpu@1 {
                        device_type = "cpu";
                #power-domain-cells = <0>;
        };
 
+       pd_disp1: disp1-power-domain@100440A0 {
+               compatible = "samsung,exynos4210-pd";
+               reg = <0x100440A0 0x20>;
+               #power-domain-cells = <0>;
+       };
+
        clock: clock-controller@10010000 {
                compatible = "samsung,exynos5250-clock";
                reg = <0x10010000 0x30000>;
                status = "disabled";
        };
 
-       tmu@10060000 {
+       tmu: tmu@10060000 {
                compatible = "samsung,exynos5250-tmu";
                reg = <0x10060000 0x100>;
                interrupts = <0 65 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu_thermal: cpu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&tmu 0>;
+
+                       cooling-maps {
+                               map0 {
+                                    /* Corresponds to 800MHz at freq_table */
+                                    cooling-device = <&cpu0 9 9>;
+                               };
+                               map1 {
+                                    /* Corresponds to 200MHz at freq_table */
+                                    cooling-device = <&cpu0 15 15>;
+                              };
+                      };
+               };
        };
 
        serial@12C00000 {
        hdmi: hdmi {
                compatible = "samsung,exynos4212-hdmi";
                reg = <0x14530000 0x70000>;
+               power-domains = <&pd_disp1>;
                interrupts = <0 95 0>;
                clocks = <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>,
                         <&clock CLK_SCLK_PIXEL>, <&clock CLK_SCLK_HDMIPHY>,
        mixer {
                compatible = "samsung,exynos5250-mixer";
                reg = <0x14450000 0x10000>;
+               power-domains = <&pd_disp1>;
                interrupts = <0 94 0>;
-               clocks = <&clock CLK_MIXER>, <&clock CLK_SCLK_HDMI>;
-               clock-names = "mixer", "sclk_hdmi";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>;
+               clock-names = "mixer", "hdmi", "sclk_hdmi";
        };
 
        dp_phy: video-phy@10040720 {
        };
 
        dp: dp-controller@145B0000 {
+               power-domains = <&pd_disp1>;
                clocks = <&clock CLK_DP>;
                clock-names = "dp";
                phys = <&dp_phy>;
        };
 
        fimd: fimd@14400000 {
+               power-domains = <&pd_disp1>;
                clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
                clock-names = "sclk_fimd", "fimd";
        };
diff --git a/arch/arm/boot/dts/exynos5420-trip-points.dtsi b/arch/arm/boot/dts/exynos5420-trip-points.dtsi
new file mode 100644 (file)
index 0000000..5d31fc1
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Device tree sources for default Exynos5420 thermal zone definition
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+polling-delay-passive = <0>;
+polling-delay = <0>;
+trips {
+       cpu-alert-0 {
+               temperature = <85000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-alert-1 {
+               temperature = <103000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-alert-2 {
+               temperature = <110000>; /* millicelsius */
+               hysteresis = <10000>; /* millicelsius */
+               type = "active";
+       };
+       cpu-crit-0 {
+               temperature = <1200000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "critical";
+       };
+};
index 9dc2e9773b30c5f5aaa22e5b3d1c1968bc1dd226..c0e98cf3514fa1fec0031984f735b02ca054af3c 100644 (file)
                compatible = "samsung,exynos5420-mixer";
                reg = <0x14450000 0x10000>;
                interrupts = <0 94 0>;
-               clocks = <&clock CLK_MIXER>, <&clock CLK_SCLK_HDMI>;
-               clock-names = "mixer", "sclk_hdmi";
+               clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+                        <&clock CLK_SCLK_HDMI>;
+               clock-names = "mixer", "hdmi", "sclk_hdmi";
                power-domains = <&disp_pd>;
        };
 
                interrupts = <0 65 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu1: tmu@10064000 {
                interrupts = <0 183 0>;
                clocks = <&clock CLK_TMU>;
                clock-names = "tmu_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu2: tmu@10068000 {
                interrupts = <0 184 0>;
                clocks = <&clock CLK_TMU>, <&clock CLK_TMU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_cpu3: tmu@1006c000 {
                interrupts = <0 185 0>;
                clocks = <&clock CLK_TMU>, <&clock CLK_TMU_GPU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
        };
 
        tmu_gpu: tmu@100a0000 {
                interrupts = <0 215 0>;
                clocks = <&clock CLK_TMU_GPU>, <&clock CLK_TMU>;
                clock-names = "tmu_apbif", "tmu_triminfo_apbif";
+               #include "exynos4412-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu0_thermal: cpu0-thermal {
+                       thermal-sensors = <&tmu_cpu0>;
+                       #include "exynos5420-trip-points.dtsi"
+               };
+               cpu1_thermal: cpu1-thermal {
+                      thermal-sensors = <&tmu_cpu1>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               cpu2_thermal: cpu2-thermal {
+                      thermal-sensors = <&tmu_cpu2>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               cpu3_thermal: cpu3-thermal {
+                      thermal-sensors = <&tmu_cpu3>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
+               gpu_thermal: gpu-thermal {
+                      thermal-sensors = <&tmu_gpu>;
+                      #include "exynos5420-trip-points.dtsi"
+               };
        };
 
         watchdog: watchdog@101D0000 {
diff --git a/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi
new file mode 100644 (file)
index 0000000..7b2fba0
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Device tree sources for Exynos5440 TMU sensor configuration
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <dt-bindings/thermal/thermal_exynos.h>
+
+#thermal-sensor-cells = <0>;
+samsung,tmu_gain = <5>;
+samsung,tmu_reference_voltage = <16>;
+samsung,tmu_noise_cancel_mode = <4>;
+samsung,tmu_efuse_value = <0x5d2d>;
+samsung,tmu_min_efuse_value = <16>;
+samsung,tmu_max_efuse_value = <76>;
+samsung,tmu_first_point_trim = <25>;
+samsung,tmu_second_point_trim = <70>;
+samsung,tmu_default_temp_offset = <25>;
+samsung,tmu_cal_type = <TYPE_ONE_POINT_TRIMMING>;
diff --git a/arch/arm/boot/dts/exynos5440-trip-points.dtsi b/arch/arm/boot/dts/exynos5440-trip-points.dtsi
new file mode 100644 (file)
index 0000000..48adfa8
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Device tree sources for default Exynos5440 thermal zone definition
+ *
+ * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+polling-delay-passive = <0>;
+polling-delay = <0>;
+trips {
+       cpu-alert-0 {
+               temperature = <100000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "active";
+       };
+       cpu-crit-0 {
+               temperature = <1050000>; /* millicelsius */
+               hysteresis = <0>; /* millicelsius */
+               type = "critical";
+       };
+};
index 8f3373cd7b878b79f2e499518a7ec774ffd06db8..59d9416b3b03f042cd05c412736c1fd432440747 100644 (file)
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
        };
 
        tmuctrl_1: tmuctrl@16011C {
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
        };
 
        tmuctrl_2: tmuctrl@160120 {
                interrupts = <0 58 0>;
                clocks = <&clock CLK_B_125>;
                clock-names = "tmu_apbif";
+               #include "exynos5440-tmu-sensor-conf.dtsi"
+       };
+
+       thermal-zones {
+               cpu0_thermal: cpu0-thermal {
+                       thermal-sensors = <&tmuctrl_0>;
+                       #include "exynos5440-trip-points.dtsi"
+               };
+               cpu1_thermal: cpu1-thermal {
+                      thermal-sensors = <&tmuctrl_1>;
+                      #include "exynos5440-trip-points.dtsi"
+               };
+               cpu2_thermal: cpu2-thermal {
+                      thermal-sensors = <&tmuctrl_2>;
+                      #include "exynos5440-trip-points.dtsi"
+               };
        };
 
        sata@210000 {
index f1cd2147421d2e0f82e2a921cc5c449d8ff6d1b4..a626e6dd8022c04defdbc56171147c04027aa48b 100644 (file)
@@ -35,6 +35,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio3 22 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_usb_h1_vbus: regulator@1 {
@@ -45,6 +46,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio1 29 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_audio: regulator@2 {
index fda4932faefda2f0b847547f15954a94347d5c40..945887d3fdb35a6588155590474479901a45671f 100644 (file)
@@ -52,6 +52,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio4 0 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_usb_otg2_vbus: regulator@1 {
@@ -62,6 +63,7 @@
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio4 2 0>;
                        enable-active-high;
+                       vin-supply = <&swbst_reg>;
                };
 
                reg_aud3v: regulator@2 {
index 59d1c297bb30f17aaab458f94e6ba52363c635cb..578fa2a54dce35482ba2d7b7fd1d42ce67a762ac 100644 (file)
@@ -87,8 +87,8 @@
                                     <14>,
                                     <15>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <64>;
+                       dma-channels = <32>;
+                       dma-requests = <64>;
                };
 
                i2c1: i2c@48070000 {
index 60403273f83e6918483641884707c8f5bd546d1e..db80f9d376fadf569655fc9660526b16b0c10739 100644 (file)
        model = "Nokia N900";
        compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3";
 
+       aliases {
+               i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+       };
+
        cpus {
                cpu@0 {
                        cpu0-supply = <&vcc>;
                compatible = "smsc,lan91c94";
                interrupt-parent = <&gpio2>;
                interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;  /* gpio54 */
-               reg = <1 0x300 0xf>;            /* 16 byte IO range at offset 0x300 */
+               reg = <1 0 0xf>;                /* 16 byte IO range */
                bank-width = <2>;
                pinctrl-names = "default";
                pinctrl-0 = <&ethernet_pins>;
index 01b71111bd558738595fde6deaa71b05c4c08e9a..3fdc84fddb70d06a2ae26db02fc2c9c9f6d8ee63 100644 (file)
@@ -92,6 +92,8 @@
                        ti,hwmods = "aes";
                        reg = <0x480c5000 0x50>;
                        interrupts = <0>;
+                       dmas = <&sdma 65 &sdma 66>;
+                       dma-names = "tx", "rx";
                };
 
                prm: prm@48306000 {
                                     <14>,
                                     <15>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <96>;
+                       dma-channels = <32>;
+                       dma-requests = <96>;
                };
 
                omap3_pmx_core: pinmux@48002030 {
                        ti,hwmods = "sham";
                        reg = <0x480c3000 0x64>;
                        interrupts = <49>;
+                       dmas = <&sdma 69>;
+                       dma-names = "rx";
                };
 
                smartreflex_core: smartreflex@480cb000 {
index 074147cebae49f965b254915240b667bffcf9d21..87401d9f4d8b02314323e5a46ee38e5b0c6e4523 100644 (file)
                                     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4a310000 {
index 19212ac6eef054e62e52454c8548a196ca08cafa..de8a3d456cf7de0e3252074e9fb4e3fcb2eca80a 100644 (file)
@@ -13,7 +13,7 @@
 
 core_thermal: core_thermal {
        polling-delay-passive = <250>; /* milliseconds */
-       polling-delay = <1000>; /* milliseconds */
+       polling-delay = <500>; /* milliseconds */
 
                        /* sensor       ID */
        thermal-sensors = <&bandgap     2>;
index 1b87aca88b77130991bb4155331983792116ddeb..bc3090f2e84b3bea10779becd939d5e9555fbffe 100644 (file)
@@ -13,7 +13,7 @@
 
 gpu_thermal: gpu_thermal {
        polling-delay-passive = <250>; /* milliseconds */
-       polling-delay = <1000>; /* milliseconds */
+       polling-delay = <500>; /* milliseconds */
 
                        /* sensor       ID */
        thermal-sensors = <&bandgap     1>;
index b321fdf42c9f3c51e3a59d4b51b27a08f4fcaba4..4a485b63a1413bf8cfda0f027ed5e7a903c68066 100644 (file)
                                     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       #dma-channels = <32>;
-                       #dma-requests = <127>;
+                       dma-channels = <32>;
+                       dma-requests = <127>;
                };
 
                gpio1: gpio@4ae10000 {
                                      <0x4A096800 0x40>; /* pll_ctrl */
                                reg-names = "phy_rx", "phy_tx", "pll_ctrl";
                                ctrl-module = <&omap_control_sata>;
-                               clocks = <&sys_clkin>;
-                               clock-names = "sysclk";
+                               clocks = <&sys_clkin>, <&sata_ref_clk>;
+                               clock-names = "sysclk", "refclk";
                                #phy-cells = <0>;
                        };
                };
        };
 };
 
+&cpu_thermal {
+       polling-delay = <500>; /* milliseconds */
+};
+
 /include/ "omap54xx-clocks.dtsi"
index 58c27466f01262a6f9ecee2058fb11dff9b5df3f..83b425fb3ac20eb1421cede5283b6a3befcdd391 100644 (file)
                ti,index-starts-at-one;
        };
 
+       dpll_core_byp_mux: dpll_core_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x012c>;
+       };
+
        dpll_core_ck: dpll_core_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-core-clock";
-               clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>;
+               clocks = <&sys_clkin>, <&dpll_core_byp_mux>;
                reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
        };
 
                clock-div = <1>;
        };
 
+       dpll_iva_byp_mux: dpll_iva_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x01ac>;
+       };
+
        dpll_iva_ck: dpll_iva_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_iva_byp_mux>;
                reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
        };
 
        };
 };
 &cm_core_clocks {
+
+       dpll_per_byp_mux: dpll_per_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x014c>;
+       };
+
        dpll_per_ck: dpll_per_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-clock";
-               clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_per_byp_mux>;
                reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
        };
 
                ti,index-starts-at-one;
        };
 
+       dpll_usb_byp_mux: dpll_usb_byp_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>;
+               ti,bit-shift = <23>;
+               reg = <0x018c>;
+       };
+
        dpll_usb_ck: dpll_usb_ck {
                #clock-cells = <0>;
                compatible = "ti,omap4-dpll-j-type-clock";
-               clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>;
+               clocks = <&sys_clkin>, <&dpll_usb_byp_mux>;
                reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
        };
 
index d771f687a13b50abad6f87ad6fb476e1d4377da9..eccc78d3220ba2e59e2994dfb4f5f20d3d3f7a91 100644 (file)
                        "mac_clk_rx", "mac_clk_tx",
                        "clk_mac_ref", "clk_mac_refout",
                        "aclk_mac", "pclk_mac";
+               status = "disabled";
        };
 
        usb_host0_ehci: usb@ff500000 {
index 261311bdf65bcb601ee5824b57ea3dcf68920db2..367af53c1b8437d30059b32abff7dd3ed7a0c992 100644 (file)
                                atmel,watchdog-type = "hardware";
                                atmel,reset-type = "all";
                                atmel,dbg-halt;
-                               atmel,idle-halt;
                                status = "disabled";
                        };
 
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00700000 0x100000>;
                        interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
index d986b41b965495bce29dc0d610a715ff4ffc0208..4303874889c69954fa894ff458bb9bfb492f33d4 100644 (file)
@@ -66,6 +66,7 @@
                gpio4 = &pioE;
                tcb0 = &tcb0;
                tcb1 = &tcb1;
+               i2c0 = &i2c0;
                i2c2 = &i2c2;
        };
        cpus {
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00600000 0x100000>;
                        interrupts = <46 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&uhpck>;
+                       clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
                        clock-names = "usb_clk", "ehci_clk", "uhpck";
                        status = "disabled";
                };
 
                                        lcdck: lcdck {
                                                #clock-cells = <0>;
-                                               reg = <4>;
-                                               clocks = <&smd>;
+                                               reg = <3>;
+                                               clocks = <&mck>;
                                        };
 
                                        smdck: smdck {
                                                reg = <50>;
                                        };
 
-                                       lcd_clk: lcd_clk {
+                                       lcdc_clk: lcdc_clk {
                                                #clock-cells = <0>;
                                                reg = <51>;
                                        };
index 252c3d1bda501f0814b73f6fa5e267c177cbff75..d9176e6061731b7c42ee792338fab3509482c603 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0xfff01000 0x1000>;
-                       interrupts = <0 156 4>;
+                       interrupts = <0 155 4>;
                        num-cs = <4>;
                        clocks = <&spi_m_clk>;
                        status = "disabled";
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&l4_sp_clk>;
+                       dmas = <&pdma 28>,
+                              <&pdma 29>;
+                       dma-names = "tx", "rx";
                };
 
                uart1: serial1@ffc03000 {
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&l4_sp_clk>;
+                       dmas = <&pdma 30>,
+                              <&pdma 31>;
+                       dma-names = "tx", "rx";
                };
 
                rst: rstmgr@ffd05000 {
index ab7891c43231de889f40efb79f7a064577c2d6ec..75742f8f96f3d1800d803a7fc2b2d3bd352413f5 100644 (file)
        model = "Olimex A10-OLinuXino-LIME";
        compatible = "olimex,a10-olinuxino-lime", "allwinner,sun4i-a10";
 
+       cpus {
+               cpu0: cpu@0 {
+                       /*
+                        * The A10-Lime is known to be unstable
+                        * when running at 1008 MHz
+                        */
+                       operating-points = <
+                               /* kHz    uV */
+                               912000  1350000
+                               864000  1300000
+                               624000  1250000
+                               >;
+                       cooling-max-level = <2>;
+               };
+       };
+
        soc@01c00000 {
                emac: ethernet@01c0b000 {
                        pinctrl-names = "default";
index 5c2925831f2038318258003ae6cd3736da71c0de..eebb7853e00bbad39916e804453929a2935cc831 100644 (file)
@@ -75,7 +75,6 @@
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1056000 1500000
                                1008000 1400000
                                912000  1350000
                                864000  1300000
@@ -83,7 +82,7 @@
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <4>;
+                       cooling-max-level = <3>;
                };
        };
 
index f8818f1edbbef27f16adadc139b8e46ae49823ad..883cb4873688f2f80ce3036ca2a60f338aa4bb67 100644 (file)
@@ -47,7 +47,6 @@
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1104000 1500000
                                1008000 1400000
                                912000  1350000
                                864000  1300000
@@ -57,7 +56,7 @@
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <6>;
+                       cooling-max-level = <5>;
                };
        };
 
index 3a8530b79f1c46200d2b7ee8bbe343198c7106d8..fdd181792b4beeb553ab55e275361d6bd6ecab07 100644 (file)
                        clock-latency = <244144>; /* 8 32k periods */
                        operating-points = <
                                /* kHz    uV */
-                               1008000 1450000
                                960000  1400000
                                912000  1400000
                                864000  1300000
                                >;
                        #cooling-cells = <2>;
                        cooling-min-level = <0>;
-                       cooling-max-level = <7>;
+                       cooling-max-level = <6>;
                };
 
                cpu@1 {
index f2670f638e97564ac8e3a01ea5bc9a1cbc24be6f..811e72bbe6429b6e6a18ac5c31c267c178d17714 100644 (file)
@@ -70,6 +70,7 @@ CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
+CONFIG_ARM_AT91_ETHER=y
 CONFIG_MACB=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
 CONFIG_DM9000=y
index e8a4c955241b88e38dfda2cc91d17b701ca6935a..06075b6d246364db1c57b1e8860e6f675d1857c5 100644 (file)
@@ -62,6 +62,17 @@ CONFIG_MACH_SPEAR1340=y
 CONFIG_ARCH_STI=y
 CONFIG_ARCH_EXYNOS=y
 CONFIG_EXYNOS5420_MCPM=y
+CONFIG_ARCH_SHMOBILE_MULTI=y
+CONFIG_ARCH_EMEV2=y
+CONFIG_ARCH_R7S72100=y
+CONFIG_ARCH_R8A73A4=y
+CONFIG_ARCH_R8A7740=y
+CONFIG_ARCH_R8A7779=y
+CONFIG_ARCH_R8A7790=y
+CONFIG_ARCH_R8A7791=y
+CONFIG_ARCH_R8A7794=y
+CONFIG_ARCH_SH73A0=y
+CONFIG_MACH_MARZEN=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_SIRF=y
 CONFIG_ARCH_TEGRA=y
@@ -84,9 +95,11 @@ CONFIG_PCI_KEYSTONE=y
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MVEBU=y
 CONFIG_PCI_TEGRA=y
+CONFIG_PCI_RCAR_GEN2=y
+CONFIG_PCI_RCAR_GEN2_PCIE=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_SMP=y
-CONFIG_NR_CPUS=8
+CONFIG_NR_CPUS=16
 CONFIG_HIGHPTE=y
 CONFIG_CMA=y
 CONFIG_ARM_APPENDED_DTB=y
@@ -130,6 +143,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_OMAP_OCP2SCP=y
+CONFIG_SIMPLE_PM_BUS=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -157,6 +171,7 @@ CONFIG_AHCI_SUNXI=y
 CONFIG_AHCI_TEGRA=y
 CONFIG_SATA_HIGHBANK=y
 CONFIG_SATA_MV=y
+CONFIG_SATA_RCAR=y
 CONFIG_NETDEVICES=y
 CONFIG_HIX5HD2_GMAC=y
 CONFIG_SUN4I_EMAC=y
@@ -167,14 +182,17 @@ CONFIG_MV643XX_ETH=y
 CONFIG_MVNETA=y
 CONFIG_KS8851=y
 CONFIG_R8169=y
+CONFIG_SH_ETH=y
 CONFIG_SMSC911X=y
 CONFIG_STMMAC_ETH=y
 CONFIG_TI_CPSW=y
 CONFIG_XILINX_EMACLITE=y
 CONFIG_AT803X_PHY=y
 CONFIG_MARVELL_PHY=y
+CONFIG_SMSC_PHY=y
 CONFIG_BROADCOM_PHY=y
 CONFIG_ICPLUS_PHY=y
+CONFIG_MICREL_PHY=y
 CONFIG_USB_PEGASUS=y
 CONFIG_USB_USBNET=y
 CONFIG_USB_NET_SMSC75XX=y
@@ -192,15 +210,18 @@ CONFIG_KEYBOARD_CROS_EC=y
 CONFIG_MOUSE_PS2_ELANTECH=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_ST1232=m
 CONFIG_TOUCHSCREEN_STMPE=y
 CONFIG_TOUCHSCREEN_SUN4I=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_MPU3050=y
 CONFIG_INPUT_AXP20X_PEK=y
+CONFIG_INPUT_ADXL34X=m
 CONFIG_SERIO_AMBAKMI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_EM=y
 CONFIG_SERIAL_8250_MT6577=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
@@ -213,6 +234,9 @@ CONFIG_SERIAL_SIRFSOC_CONSOLE=y
 CONFIG_SERIAL_TEGRA=y
 CONFIG_SERIAL_IMX=y
 CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=20
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_VT8500=y
@@ -233,19 +257,26 @@ CONFIG_I2C_MUX_PCA954x=y
 CONFIG_I2C_MUX_PINCTRL=y
 CONFIG_I2C_CADENCE=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_I2C_GPIO=m
 CONFIG_I2C_EXYNOS5=y
 CONFIG_I2C_MV64XXX=y
+CONFIG_I2C_RIIC=y
 CONFIG_I2C_S3C2410=y
+CONFIG_I2C_SH_MOBILE=y
 CONFIG_I2C_SIRF=y
-CONFIG_I2C_TEGRA=y
 CONFIG_I2C_ST=y
-CONFIG_SPI=y
+CONFIG_I2C_TEGRA=y
 CONFIG_I2C_XILINX=y
-CONFIG_SPI_DAVINCI=y
+CONFIG_I2C_RCAR=y
+CONFIG_SPI=y
 CONFIG_SPI_CADENCE=y
+CONFIG_SPI_DAVINCI=y
 CONFIG_SPI_OMAP24XX=y
 CONFIG_SPI_ORION=y
 CONFIG_SPI_PL022=y
+CONFIG_SPI_RSPI=y
+CONFIG_SPI_SH_MSIOF=m
+CONFIG_SPI_SH_HSPI=y
 CONFIG_SPI_SIRF=y
 CONFIG_SPI_SUN4I=y
 CONFIG_SPI_SUN6I=y
@@ -259,12 +290,15 @@ CONFIG_PINCTRL_PALMAS=y
 CONFIG_PINCTRL_APQ8084=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
-CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_DAVINCI=y
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_EM=y
+CONFIG_GPIO_RCAR=y
 CONFIG_GPIO_XILINX=y
 CONFIG_GPIO_ZYNQ=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCF857X=y
 CONFIG_GPIO_TWL4030=y
 CONFIG_GPIO_PALMAS=y
 CONFIG_GPIO_SYSCON=y
@@ -276,10 +310,12 @@ CONFIG_POWER_RESET_AS3722=y
 CONFIG_POWER_RESET_GPIO=y
 CONFIG_POWER_RESET_KEYSTONE=y
 CONFIG_POWER_RESET_SUN6I=y
+CONFIG_POWER_RESET_RMOBILE=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM95245=y
 CONFIG_THERMAL=y
 CONFIG_CPU_THERMAL=y
+CONFIG_RCAR_THERMAL=y
 CONFIG_ARMADA_THERMAL=y
 CONFIG_DAVINCI_WATCHDOG
 CONFIG_ST_THERMAL_SYSCFG=y
@@ -290,6 +326,7 @@ CONFIG_ARM_SP805_WATCHDOG=y
 CONFIG_ORION_WATCHDOG=y
 CONFIG_SUNXI_WATCHDOG=y
 CONFIG_MESON_WATCHDOG=y
+CONFIG_MFD_AS3711=y
 CONFIG_MFD_AS3722=y
 CONFIG_MFD_BCM590XX=y
 CONFIG_MFD_AXP20X=y
@@ -304,13 +341,16 @@ CONFIG_MFD_TPS65090=y
 CONFIG_MFD_TPS6586X=y
 CONFIG_MFD_TPS65910=y
 CONFIG_REGULATOR_AB8500=y
+CONFIG_REGULATOR_AS3711=y
 CONFIG_REGULATOR_AS3722=y
 CONFIG_REGULATOR_AXP20X=y
 CONFIG_REGULATOR_BCM590XX=y
+CONFIG_REGULATOR_DA9210=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MFD_SYSCON=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_REGULATOR_MAX8907=y
+CONFIG_REGULATOR_MAX8973=y
 CONFIG_REGULATOR_MAX77686=y
 CONFIG_REGULATOR_PALMAS=y
 CONFIG_REGULATOR_S2MPS11=y
@@ -324,18 +364,32 @@ CONFIG_REGULATOR_TWL4030=y
 CONFIG_REGULATOR_VEXPRESS=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=y
 CONFIG_USB_GSPCA=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=m
+CONFIG_SOC_CAMERA_PLATFORM=m
+CONFIG_VIDEO_RCAR_VIN=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_RENESAS_VSP1=m
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+CONFIG_VIDEO_ADV7180=m
 CONFIG_DRM=y
+CONFIG_DRM_RCAR_DU=m
 CONFIG_DRM_TEGRA=y
 CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_FB_ARMCLCD=y
 CONFIG_FB_WM8505=y
+CONFIG_FB_SH_MOBILE_LCDC=y
 CONFIG_FB_SIMPLE=y
+CONFIG_FB_SH_MOBILE_MERAM=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_AS3711=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_SOUND=y
@@ -343,6 +397,8 @@ CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SH4_FSI=m
+CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_TEGRA=y
 CONFIG_SND_SOC_TEGRA_RT5640=y
 CONFIG_SND_SOC_TEGRA_WM8753=y
@@ -350,6 +406,8 @@ CONFIG_SND_SOC_TEGRA_WM8903=y
 CONFIG_SND_SOC_TEGRA_TRIMSLICE=y
 CONFIG_SND_SOC_TEGRA_ALC5632=y
 CONFIG_SND_SOC_TEGRA_MAX98090=y
+CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_WM8978=m
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_MVEBU=y
@@ -362,6 +420,8 @@ CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_STI=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_RENESAS_USBHS=m
 CONFIG_USB_STORAGE=y
 CONFIG_USB_DWC3=y
 CONFIG_USB_CHIPIDEA=y
@@ -374,6 +434,10 @@ CONFIG_SAMSUNG_USB3PHY=y
 CONFIG_USB_GPIO_VBUS=y
 CONFIG_USB_ISP1301=y
 CONFIG_USB_MXS_PHY=y
+CONFIG_USB_RCAR_PHY=m
+CONFIG_USB_RCAR_GEN2_PHY=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS_UDC=m
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_ARMMMCI=y
@@ -392,12 +456,14 @@ CONFIG_MMC_SDHCI_ST=y
 CONFIG_MMC_OMAP=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_MMC_MVSDIO=y
-CONFIG_MMC_SUNXI=y
+CONFIG_MMC_SDHI=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_IDMAC=y
 CONFIG_MMC_DW_PLTFM=y
 CONFIG_MMC_DW_EXYNOS=y
 CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_MMC_SH_MMCIF=y
+CONFIG_MMC_SUNXI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
@@ -421,10 +487,12 @@ CONFIG_RTC_DRV_AS3722=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_MAX8907=y
 CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_RS5C372=m
 CONFIG_RTC_DRV_PALMAS=y
 CONFIG_RTC_DRV_TWL4030=y
 CONFIG_RTC_DRV_TPS6586X=y
 CONFIG_RTC_DRV_TPS65910=y
+CONFIG_RTC_DRV_S35390A=m
 CONFIG_RTC_DRV_EM3027=y
 CONFIG_RTC_DRV_PL031=y
 CONFIG_RTC_DRV_VT8500=y
@@ -436,6 +504,9 @@ CONFIG_DMADEVICES=y
 CONFIG_DW_DMAC=y
 CONFIG_MV_XOR=y
 CONFIG_TEGRA20_APB_DMA=y
+CONFIG_SH_DMAE=y
+CONFIG_RCAR_AUDMAC_PP=m
+CONFIG_RCAR_DMAC=y
 CONFIG_STE_DMA40=y
 CONFIG_SIRF_DMA=y
 CONFIG_TI_EDMA=y
@@ -468,6 +539,7 @@ CONFIG_IIO=y
 CONFIG_XILINX_XADC=y
 CONFIG_AK8975=y
 CONFIG_PWM=y
+CONFIG_PWM_RENESAS_TPU=y
 CONFIG_PWM_TEGRA=y
 CONFIG_PWM_VT8500=y
 CONFIG_PHY_HIX5HD2_SATA=y
index b7386524c356619ceb9889553144e1292d2e1904..8e108599e1af401451aeeb01a9e6b7a1752c7c0d 100644 (file)
@@ -114,6 +114,7 @@ CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC_BCH=y
 CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_OMAP_BCH=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_OMAP2=y
@@ -248,6 +249,7 @@ CONFIG_TWL6040_CORE=y
 CONFIG_REGULATOR_PALMAS=y
 CONFIG_REGULATOR_PBIAS=y
 CONFIG_REGULATOR_TI_ABB=y
+CONFIG_REGULATOR_TPS62360=m
 CONFIG_REGULATOR_TPS65023=y
 CONFIG_REGULATOR_TPS6507X=y
 CONFIG_REGULATOR_TPS65217=y
@@ -374,7 +376,8 @@ CONFIG_PWM_TIEHRPWM=m
 CONFIG_PWM_TWL=m
 CONFIG_PWM_TWL_LED=m
 CONFIG_OMAP_USB2=m
-CONFIG_TI_PIPE3=m
+CONFIG_TI_PIPE3=y
+CONFIG_TWL4030_USB=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
index 41d856effe6cadcf928ddd6f6fd8efa6edbc951d..510c747c65b446b173fb241d15da8c16983a989e 100644 (file)
@@ -3,8 +3,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
index 38840a8129240f7e89af853521b9aa2bb398c40f..8f6a5702b69619eb6d332db0dbf45853b527faa4 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_PERF_EVENTS=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_SMP=y
+CONFIG_NR_CPUS=8
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_HIGHPTE=y
index f489fdaa19b8ff127944d6bde8a7e0fa806848c4..37fe607a4ede57755a112da4f17fdd8d4ae44f8a 100644 (file)
@@ -118,8 +118,8 @@ CONFIG_HID_ZEROPLUS=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_MON=y
-CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_ISP1760=y
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_NEW_LEDS=y
index 71e5fc7cfb18f489f3adadb20c6f8049421fb079..1d1800f71c5b3d372d33ec1e43acdaa35e17d3be 100644 (file)
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__  7
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
 #endif
 
 #ifdef __thumb__
 # define adrl adr
 #endif
 
-#if __ARM_ARCH__>=7
+#if __ARM_MAX_ARCH__>=7
+.arch  armv7-a
+.fpu   neon
+
 .text
 .syntax        unified         @ ARMv7-capable assembler is expected to handle this
 #ifdef __thumb2__
@@ -74,8 +78,6 @@
 .code   32
 #endif
 
-.fpu   neon
-
 .type  _bsaes_decrypt8,%function
 .align 4
 _bsaes_decrypt8:
@@ -2095,9 +2097,11 @@ bsaes_xts_decrypt:
        vld1.8  {q8}, [r0]                      @ initial tweak
        adr     r2, .Lxts_magic
 
+#ifndef        XTS_CHAIN_TWEAK
        tst     r9, #0xf                        @ if not multiple of 16
        it      ne                              @ Thumb2 thing, sanity check in ARM
        subne   r9, #0x10                       @ subtract another 16 bytes
+#endif
        subs    r9, #0x80
 
        blo     .Lxts_dec_short
index be068db960ee0006ac1aa25a4e69b95265404844..a4d3856e7d2477ec6379f1f10a9121e32f36a974 100644 (file)
@@ -701,14 +701,18 @@ $code.=<<___;
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__  7
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
 #endif
 
 #ifdef __thumb__
 # define adrl adr
 #endif
 
-#if __ARM_ARCH__>=7
+#if __ARM_MAX_ARCH__>=7
+.arch  armv7-a
+.fpu   neon
+
 .text
 .syntax        unified         @ ARMv7-capable assembler is expected to handle this
 #ifdef __thumb2__
@@ -717,8 +721,6 @@ $code.=<<___;
 .code   32
 #endif
 
-.fpu   neon
-
 .type  _bsaes_decrypt8,%function
 .align 4
 _bsaes_decrypt8:
@@ -2076,9 +2078,11 @@ bsaes_xts_decrypt:
        vld1.8  {@XMM[8]}, [r0]                 @ initial tweak
        adr     $magic, .Lxts_magic
 
+#ifndef        XTS_CHAIN_TWEAK
        tst     $len, #0xf                      @ if not multiple of 16
        it      ne                              @ Thumb2 thing, sanity check in ARM
        subne   $len, #0x10                     @ subtract another 16 bytes
+#endif
        subs    $len, #0x80
 
        blo     .Lxts_dec_short
index 37ca2a4c6f0944598cacb0fbdab33c716258ea4e..4cf48c3aca13e9afe7b852660afa4d5945994a93 100644 (file)
@@ -149,29 +149,28 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
        (__boundary - 1 < (end) - 1)? __boundary: (end);                \
 })
 
+#define kvm_pgd_index(addr)                    pgd_index(addr)
+
 static inline bool kvm_page_empty(void *ptr)
 {
        struct page *ptr_page = virt_to_page(ptr);
        return page_count(ptr_page) == 1;
 }
 
-
 #define kvm_pte_table_empty(kvm, ptep) kvm_page_empty(ptep)
 #define kvm_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp)
 #define kvm_pud_table_empty(kvm, pudp) (0)
 
 #define KVM_PREALLOC_LEVEL     0
 
-static inline int kvm_prealloc_hwpgd(struct kvm *kvm, pgd_t *pgd)
+static inline void *kvm_get_hwpgd(struct kvm *kvm)
 {
-       return 0;
+       return kvm->arch.pgd;
 }
 
-static inline void kvm_free_hwpgd(struct kvm *kvm) { }
-
-static inline void *kvm_get_hwpgd(struct kvm *kvm)
+static inline unsigned int kvm_get_hwpgd_size(void)
 {
-       return kvm->arch.pgd;
+       return PTRS_PER_S2_PGD * sizeof(pgd_t);
 }
 
 struct kvm;
@@ -207,7 +206,7 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
 
        bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached;
 
-       VM_BUG_ON(size & PAGE_MASK);
+       VM_BUG_ON(size & ~PAGE_MASK);
 
        if (!need_flush && !icache_is_pipt())
                goto vipt_cache;
index 80a6501b4d5068ceed534f43ba3b1d59083d0b2a..c3c45e628e33bb9bf80a96014f1b510ede78580c 100644 (file)
 #define AT91_DBGU 0xfc00c000 /* SAMA5D4_BASE_USART3 */
 #endif
 
-/* Keep in sync with mach-at91/include/mach/hardware.h */
+#ifdef CONFIG_MMU
 #define AT91_IO_P2V(x) ((x) - 0x01000000)
+#else
+#define AT91_IO_P2V(x) (x)
+#endif
 
 #define AT91_DBGU_SR           (0x14)  /* Status Register */
 #define AT91_DBGU_THR          (0x1c)  /* Transmitter Holding Register */
index e55408e965596964ff8c8708dcfec529a559b1bc..1d60bebea4b8b7923748cd6eb2d25fc4299bfc32 100644 (file)
@@ -246,12 +246,9 @@ static int __get_cpu_architecture(void)
                if (cpu_arch)
                        cpu_arch += CPU_ARCH_ARMv3;
        } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
-               unsigned int mmfr0;
-
                /* Revised CPUID format. Read the Memory Model Feature
                 * Register 0 and check for VMSAv7 or PMSAv7 */
-               asm("mrc        p15, 0, %0, c0, c1, 4"
-                   : "=r" (mmfr0));
+               unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0);
                if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
                    (mmfr0 & 0x000000f0) >= 0x00000030)
                        cpu_arch = CPU_ARCH_ARMv7;
index 07e7eb1d7ab63b0417f8a54203620988b72228c4..5560f74f9eeef1e3e4d2c9c39fc672e539eee93f 100644 (file)
@@ -540,7 +540,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                kvm_guest_exit();
-               trace_kvm_exit(*vcpu_pc(vcpu));
+               trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
                /*
                 * We may have taken a host interrupt in HYP mode (ie
                 * while executing the guest). This interrupt is still
index 3e6859bc3e1170fc83489be9ba51a15c97b148a5..5656d79c5a44f4d2ca816e15b647abf29a114e0b 100644 (file)
@@ -290,7 +290,7 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
        phys_addr_t addr = start, end = start + size;
        phys_addr_t next;
 
-       pgd = pgdp + pgd_index(addr);
+       pgd = pgdp + kvm_pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
                if (!pgd_none(*pgd))
@@ -355,7 +355,7 @@ static void stage2_flush_memslot(struct kvm *kvm,
        phys_addr_t next;
        pgd_t *pgd;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
                stage2_flush_puds(kvm, pgd, addr, next);
@@ -632,6 +632,20 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
                                     __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
 }
 
+/* Free the HW pgd, one page at a time */
+static void kvm_free_hwpgd(void *hwpgd)
+{
+       free_pages_exact(hwpgd, kvm_get_hwpgd_size());
+}
+
+/* Allocate the HW PGD, making sure that each page gets its own refcount */
+static void *kvm_alloc_hwpgd(void)
+{
+       unsigned int size = kvm_get_hwpgd_size();
+
+       return alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+}
+
 /**
  * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
  * @kvm:       The KVM struct pointer for the VM.
@@ -645,15 +659,31 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
  */
 int kvm_alloc_stage2_pgd(struct kvm *kvm)
 {
-       int ret;
        pgd_t *pgd;
+       void *hwpgd;
 
        if (kvm->arch.pgd != NULL) {
                kvm_err("kvm_arch already initialized?\n");
                return -EINVAL;
        }
 
+       hwpgd = kvm_alloc_hwpgd();
+       if (!hwpgd)
+               return -ENOMEM;
+
+       /* When the kernel uses more levels of page tables than the
+        * guest, we allocate a fake PGD and pre-populate it to point
+        * to the next-level page table, which will be the real
+        * initial page table pointed to by the VTTBR.
+        *
+        * When KVM_PREALLOC_LEVEL==2, we allocate a single page for
+        * the PMD and the kernel will use folded pud.
+        * When KVM_PREALLOC_LEVEL==1, we allocate 2 consecutive PUD
+        * pages.
+        */
        if (KVM_PREALLOC_LEVEL > 0) {
+               int i;
+
                /*
                 * Allocate fake pgd for the page table manipulation macros to
                 * work.  This is not used by the hardware and we have no
@@ -661,30 +691,32 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
                 */
                pgd = (pgd_t *)kmalloc(PTRS_PER_S2_PGD * sizeof(pgd_t),
                                       GFP_KERNEL | __GFP_ZERO);
+
+               if (!pgd) {
+                       kvm_free_hwpgd(hwpgd);
+                       return -ENOMEM;
+               }
+
+               /* Plug the HW PGD into the fake one. */
+               for (i = 0; i < PTRS_PER_S2_PGD; i++) {
+                       if (KVM_PREALLOC_LEVEL == 1)
+                               pgd_populate(NULL, pgd + i,
+                                            (pud_t *)hwpgd + i * PTRS_PER_PUD);
+                       else if (KVM_PREALLOC_LEVEL == 2)
+                               pud_populate(NULL, pud_offset(pgd, 0) + i,
+                                            (pmd_t *)hwpgd + i * PTRS_PER_PMD);
+               }
        } else {
                /*
                 * Allocate actual first-level Stage-2 page table used by the
                 * hardware for Stage-2 page table walks.
                 */
-               pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, S2_PGD_ORDER);
+               pgd = (pgd_t *)hwpgd;
        }
 
-       if (!pgd)
-               return -ENOMEM;
-
-       ret = kvm_prealloc_hwpgd(kvm, pgd);
-       if (ret)
-               goto out_err;
-
        kvm_clean_pgd(pgd);
        kvm->arch.pgd = pgd;
        return 0;
-out_err:
-       if (KVM_PREALLOC_LEVEL > 0)
-               kfree(pgd);
-       else
-               free_pages((unsigned long)pgd, S2_PGD_ORDER);
-       return ret;
 }
 
 /**
@@ -785,11 +817,10 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
                return;
 
        unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
-       kvm_free_hwpgd(kvm);
+       kvm_free_hwpgd(kvm_get_hwpgd(kvm));
        if (KVM_PREALLOC_LEVEL > 0)
                kfree(kvm->arch.pgd);
-       else
-               free_pages((unsigned long)kvm->arch.pgd, S2_PGD_ORDER);
+
        kvm->arch.pgd = NULL;
 }
 
@@ -799,7 +830,7 @@ static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache
        pgd_t *pgd;
        pud_t *pud;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        if (WARN_ON(pgd_none(*pgd))) {
                if (!cache)
                        return NULL;
@@ -1089,7 +1120,7 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
        pgd_t *pgd;
        phys_addr_t next;
 
-       pgd = kvm->arch.pgd + pgd_index(addr);
+       pgd = kvm->arch.pgd + kvm_pgd_index(addr);
        do {
                /*
                 * Release kvm_mmu_lock periodically if the memory region is
index 881874b1a036ce117e01c2c6e124b28fb2506b89..6817664b46b80419047066686a47a8bc7953ebeb 100644 (file)
@@ -25,18 +25,22 @@ TRACE_EVENT(kvm_entry,
 );
 
 TRACE_EVENT(kvm_exit,
-       TP_PROTO(unsigned long vcpu_pc),
-       TP_ARGS(vcpu_pc),
+       TP_PROTO(unsigned int exit_reason, unsigned long vcpu_pc),
+       TP_ARGS(exit_reason, vcpu_pc),
 
        TP_STRUCT__entry(
+               __field(        unsigned int,   exit_reason     )
                __field(        unsigned long,  vcpu_pc         )
        ),
 
        TP_fast_assign(
+               __entry->exit_reason            = exit_reason;
                __entry->vcpu_pc                = vcpu_pc;
        ),
 
-       TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
+       TP_printk("HSR_EC: 0x%04x, PC: 0x%08lx",
+                 __entry->exit_reason,
+                 __entry->vcpu_pc)
 );
 
 TRACE_EVENT(kvm_guest_fault,
index 8423be76080eaa293e8f1d36f740548ddbad6973..52241207a82a3d3a802a90c1fe47e78150e8d5ba 100644 (file)
@@ -2,5 +2,7 @@ config MACH_ASM9260
        bool "Alphascale ASM9260"
        depends on ARCH_MULTI_V5
        select CPU_ARM926T
+       select ASM9260_TIMER
+       select GENERIC_CLOCKEVENTS
        help
          Support for Alphascale ASM9260 based platform.
index 5e34fb1433098aee3916f2b4c3019a14d2aa5ba8..aa4116e9452f725e0f63241cfc083576c665be19 100644 (file)
@@ -270,37 +270,35 @@ static void __init at91_pm_sram_init(void)
        phys_addr_t sram_pbase;
        unsigned long sram_base;
        struct device_node *node;
-       struct platform_device *pdev;
+       struct platform_device *pdev = NULL;
 
-       node = of_find_compatible_node(NULL, NULL, "mmio-sram");
-       if (!node) {
-               pr_warn("%s: failed to find sram node!\n", __func__);
-               return;
+       for_each_compatible_node(node, NULL, "mmio-sram") {
+               pdev = of_find_device_by_node(node);
+               if (pdev) {
+                       of_node_put(node);
+                       break;
+               }
        }
 
-       pdev = of_find_device_by_node(node);
        if (!pdev) {
                pr_warn("%s: failed to find sram device!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_pool = dev_get_gen_pool(&pdev->dev);
        if (!sram_pool) {
                pr_warn("%s: sram pool unavailable!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_base = gen_pool_alloc(sram_pool, at91_slow_clock_sz);
        if (!sram_base) {
                pr_warn("%s: unable to alloc ocram!\n", __func__);
-               goto put_node;
+               return;
        }
 
        sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base);
        slow_clock = __arm_ioremap_exec(sram_pbase, at91_slow_clock_sz, false);
-
-put_node:
-       of_node_put(node);
 }
 #endif
 
index d2c89963af2d168179e01e72d51f6684decc8d5e..86c0aa819d2590aae5af7146e5e3a4ebeb086e35 100644 (file)
@@ -44,7 +44,7 @@ static inline void at91rm9200_standby(void)
                "    mcr    p15, 0, %0, c7, c0, 4\n\t"
                "    str    %5, [%1, %2]"
                :
-               : "r" (0), "r" (AT91_BASE_SYS), "r" (AT91RM9200_SDRAMC_LPR),
+               : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91RM9200_SDRAMC_LPR),
                  "r" (1), "r" (AT91RM9200_SDRAMC_SRR),
                  "r" (lpr));
 }
index 556151e85ec4c71712373098ce731c68674a757b..931f0e302c035ecc33a138ec0bd61dc910321c66 100644 (file)
  */
 #undef SLOWDOWN_MASTER_CLOCK
 
-#define MCKRDY_TIMEOUT         1000
-#define MOSCRDY_TIMEOUT        1000
-#define PLLALOCK_TIMEOUT       1000
-#define PLLBLOCK_TIMEOUT       1000
-
 pmc    .req    r0
 sdramc .req    r1
 ramc1  .req    r2
@@ -41,60 +36,42 @@ tmp2        .req    r5
  * Wait until master clock is ready (after switching master clock source)
  */
        .macro wait_mckrdy
-       mov     tmp2, #MCKRDY_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_MCKRDY
        beq     1b
-2:
        .endm
 
 /*
  * Wait until master oscillator has stabilized.
  */
        .macro wait_moscrdy
-       mov     tmp2, #MOSCRDY_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_MOSCS
        beq     1b
-2:
        .endm
 
 /*
  * Wait until PLLA has locked.
  */
        .macro wait_pllalock
-       mov     tmp2, #PLLALOCK_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_LOCKA
        beq     1b
-2:
        .endm
 
 /*
  * Wait until PLLB has locked.
  */
        .macro wait_pllblock
-       mov     tmp2, #PLLBLOCK_TIMEOUT
-1:     sub     tmp2, tmp2, #1
-       cmp     tmp2, #0
-       beq     2f
-       ldr     tmp1, [pmc, #AT91_PMC_SR]
+1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
        tst     tmp1, #AT91_PMC_LOCKB
        beq     1b
-2:
        .endm
 
        .text
 
+       .arm
+
 /* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
  *                     void __iomem *ramc1, int memctrl)
  */
@@ -134,6 +111,16 @@ ddr_sr_enable:
        cmp     memctrl, #AT91_MEMCTRL_DDRSDR
        bne     sdr_sr_enable
 
+       /* LPDDR1 --> force DDR2 mode during self-refresh */
+       ldr     tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+       str     tmp1, .saved_sam9_mdr
+       bic     tmp1, tmp1, #~AT91_DDRSDRC_MD
+       cmp     tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+       ldreq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+       biceq   tmp1, tmp1, #AT91_DDRSDRC_MD
+       orreq   tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
+       streq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+
        /* prepare for DDRAM self-refresh mode */
        ldr     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
        str     tmp1, .saved_sam9_lpr
@@ -142,14 +129,26 @@ ddr_sr_enable:
 
        /* figure out if we use the second ram controller */
        cmp     ramc1, #0
-       ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-       strne   tmp2, .saved_sam9_lpr1
-       bicne   tmp2, #AT91_DDRSDRC_LPCB
-       orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+       beq     ddr_no_2nd_ctrl
+
+       ldr     tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+       str     tmp2, .saved_sam9_mdr1
+       bic     tmp2, tmp2, #~AT91_DDRSDRC_MD
+       cmp     tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+       ldreq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+       biceq   tmp2, tmp2, #AT91_DDRSDRC_MD
+       orreq   tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
+       streq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+
+       ldr     tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+       str     tmp2, .saved_sam9_lpr1
+       bic     tmp2, #AT91_DDRSDRC_LPCB
+       orr     tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
        /* Enable DDRAM self-refresh mode */
+       str     tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+ddr_no_2nd_ctrl:
        str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-       strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
        b       sdr_sr_done
 
@@ -208,6 +207,7 @@ sdr_sr_done:
        /* Turn off the main oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
        bic     tmp1, tmp1, #AT91_PMC_MOSCEN
+       orr     tmp1, tmp1, #AT91_PMC_KEY
        str     tmp1, [pmc, #AT91_CKGR_MOR]
 
        /* Wait for interrupt */
@@ -216,6 +216,7 @@ sdr_sr_done:
        /* Turn on the main oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
        orr     tmp1, tmp1, #AT91_PMC_MOSCEN
+       orr     tmp1, tmp1, #AT91_PMC_KEY
        str     tmp1, [pmc, #AT91_CKGR_MOR]
 
        wait_moscrdy
@@ -280,12 +281,17 @@ sdr_sr_done:
         */
        cmp     memctrl, #AT91_MEMCTRL_DDRSDR
        bne     sdr_en_restore
+       /* Restore MDR in case of LPDDR1 */
+       ldr     tmp1, .saved_sam9_mdr
+       str     tmp1, [sdramc, #AT91_DDRSDRC_MDR]
        /* Restore LPR on AT91 with DDRAM */
        ldr     tmp1, .saved_sam9_lpr
        str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 
        /* if we use the second ram controller */
        cmp     ramc1, #0
+       ldrne   tmp2, .saved_sam9_mdr1
+       strne   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
        ldrne   tmp2, .saved_sam9_lpr1
        strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
@@ -319,5 +325,11 @@ ram_restored:
 .saved_sam9_lpr1:
        .word 0
 
+.saved_sam9_mdr:
+       .word 0
+
+.saved_sam9_mdr1:
+       .word 0
+
 ENTRY(at91_slow_clock_sz)
        .word .-at91_slow_clock
index 3f32c47a6d74e780f429e5a9331c0737c2cb64d7..d2e9f12d12f187e1e2c40f11748f75bbe0a283f2 100644 (file)
@@ -126,8 +126,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
  */
 void exynos_cpu_power_down(int cpu)
 {
-       if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") ||
-               of_machine_is_compatible("samsung,exynos5800"))) {
+       if (cpu == 0 && (soc_is_exynos5420() || soc_is_exynos5800())) {
                /*
                 * Bypass power down for CPU0 during suspend. Check for
                 * the SYS_PWR_REG value to decide if we are suspending
index 20f267121b3e7876e4ab806ab6c2f655e9467499..37266a8264372a9d8ab898aec6389476f707869f 100644 (file)
@@ -161,6 +161,34 @@ no_clk:
                of_genpd_add_provider_simple(np, &pd->pd);
        }
 
+       /* Assign the child power domains to their parents */
+       for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
+               struct generic_pm_domain *child_domain, *parent_domain;
+               struct of_phandle_args args;
+
+               args.np = np;
+               args.args_count = 0;
+               child_domain = of_genpd_get_from_provider(&args);
+               if (!child_domain)
+                       continue;
+
+               if (of_parse_phandle_with_args(np, "power-domains",
+                                        "#power-domain-cells", 0, &args) != 0)
+                       continue;
+
+               parent_domain = of_genpd_get_from_provider(&args);
+               if (!parent_domain)
+                       continue;
+
+               if (pm_genpd_add_subdomain(parent_domain, child_domain))
+                       pr_warn("%s failed to add subdomain: %s\n",
+                               parent_domain->name, child_domain->name);
+               else
+                       pr_info("%s has as child subdomain: %s.\n",
+                               parent_domain->name, child_domain->name);
+               of_node_put(np);
+       }
+
        return 0;
 }
 arch_initcall(exynos4_pm_init_power_domain);
index 52e2b1a2fddbfcf7485d1c504c4e66cec3609388..318d127df147c2515f5ecb6674bec31423d790b1 100644 (file)
@@ -87,8 +87,8 @@ static unsigned int exynos_pmu_spare3;
 static u32 exynos_irqwake_intmask = 0xffffffff;
 
 static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
-       { 73, BIT(1) }, /* RTC alarm */
-       { 74, BIT(2) }, /* RTC tick */
+       { 105, BIT(1) }, /* RTC alarm */
+       { 106, BIT(2) }, /* RTC tick */
        { /* sentinel */ },
 };
 
index 4ad6e473cf83ab82e3a769ddcae8956762f47be9..9de3412af4063ccd4ae7b8f2a176e9300020947a 100644 (file)
@@ -211,8 +211,9 @@ static void __init imx6q_1588_init(void)
         * set bit IOMUXC_GPR1[21].  Or the PTP clock must be from pad
         * (external OSC), and we need to clear the bit.
         */
-       clksel = ptp_clk == enet_ref ? IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
-                                      IMX6Q_GPR1_ENET_CLK_SEL_PAD;
+       clksel = clk_is_match(ptp_clk, enet_ref) ?
+                               IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
+                               IMX6Q_GPR1_ENET_CLK_SEL_PAD;
        gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
        if (!IS_ERR(gpr))
                regmap_update_bits(gpr, IOMUXC_GPR1,
index 61bfe584a9d7fad4a7204d3ddb2a0a42afe3a23b..fc832040c6e979f139e272c73a47d167a65d8df5 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/smc91x.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -46,15 +47,20 @@ static struct resource smc91x_resources[] = {
        [1] = {
                .start  = MSM_GPIO_TO_INT(49),
                .end    = MSM_GPIO_TO_INT(49),
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static struct platform_device *devices[] __initdata = {
index 4c748616ef47eb9de63d751072e8d779fc3ffe44..10016a3bc69826351830ea53f822c7a8e3c4f033 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/usb/msm_hsusb.h>
 #include <linux/err.h>
 #include <linux/clkdev.h>
+#include <linux/smc91x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -49,15 +50,20 @@ static struct resource smc91x_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        [1] = {
-               .flags = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static int __init msm_init_smc91x(void)
index 2a2f4d56e4c85ea599b295a10d09c2bf922bdc79..25f1beea453e0252234b3c62d7f53de75e6ed3f3 100644 (file)
@@ -720,6 +720,8 @@ static const char * __init omap_get_family(void)
                return kasprintf(GFP_KERNEL, "OMAP4");
        else if (soc_is_omap54xx())
                return kasprintf(GFP_KERNEL, "OMAP5");
+       else if (soc_is_am33xx() || soc_is_am335x())
+               return kasprintf(GFP_KERNEL, "AM33xx");
        else if (soc_is_am43xx())
                return kasprintf(GFP_KERNEL, "AM43xx");
        else if (soc_is_dra7xx())
index 92afb723dcfc2364aca9e711a3fb4bf9c5245e12..355b089368715427627dd39f1014ed7024ae8459 100644 (file)
@@ -1692,16 +1692,15 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
        if (ret == -EBUSY)
                pr_warn("omap_hwmod: %s: failed to hardreset\n", oh->name);
 
-       if (!ret) {
+       if (oh->clkdm) {
                /*
                 * Set the clockdomain to HW_AUTO, assuming that the
                 * previous state was HW_AUTO.
                 */
-               if (oh->clkdm && hwsup)
+               if (hwsup)
                        clkdm_allow_idle(oh->clkdm);
-       } else {
-               if (oh->clkdm)
-                       clkdm_hwmod_disable(oh->clkdm, oh);
+
+               clkdm_hwmod_disable(oh->clkdm, oh);
        }
 
        return ret;
@@ -2698,6 +2697,7 @@ static int __init _register(struct omap_hwmod *oh)
        INIT_LIST_HEAD(&oh->master_ports);
        INIT_LIST_HEAD(&oh->slave_ports);
        spin_lock_init(&oh->_lock);
+       lockdep_set_class(&oh->_lock, &oh->hwmod_key);
 
        oh->_state = _HWMOD_STATE_REGISTERED;
 
index 9d4bec6ee7424c2643600ded08e0a0d9bef093fa..9611c91d9b82154e6d5d7f46c75c1b1ab6ffd588 100644 (file)
@@ -674,6 +674,7 @@ struct omap_hwmod {
        u32                             _sysc_cache;
        void __iomem                    *_mpu_rt_va;
        spinlock_t                      _lock;
+       struct lock_class_key           hwmod_key; /* unique lock class */
        struct list_head                node;
        struct omap_hwmod_ocp_if        *_mpu_port;
        unsigned int                    (*xlate_irq)(unsigned int);
index e8692e7675b865833e31b0b07c130d8512c3b221..16fe7a1b7a3578069746371dc789e51308cc2134 100644 (file)
@@ -1466,53 +1466,16 @@ static struct omap_hwmod dra7xx_ocp2scp3_hwmod = {
  *
  */
 
-static struct omap_hwmod_class dra7xx_pcie_hwmod_class = {
+static struct omap_hwmod_class dra7xx_pciess_hwmod_class = {
        .name   = "pcie",
 };
 
 /* pcie1 */
-static struct omap_hwmod dra7xx_pcie1_hwmod = {
+static struct omap_hwmod dra7xx_pciess1_hwmod = {
        .name           = "pcie1",
-       .class          = &dra7xx_pcie_hwmod_class,
+       .class          = &dra7xx_pciess_hwmod_class,
        .clkdm_name     = "pcie_clkdm",
        .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs   = DRA7XX_CM_PCIE_CLKSTCTRL_OFFSET,
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* pcie2 */
-static struct omap_hwmod dra7xx_pcie2_hwmod = {
-       .name           = "pcie2",
-       .class          = &dra7xx_pcie_hwmod_class,
-       .clkdm_name     = "pcie_clkdm",
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_PCIE_CLKSTCTRL_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/*
- * 'PCIE PHY' class
- *
- */
-
-static struct omap_hwmod_class dra7xx_pcie_phy_hwmod_class = {
-       .name   = "pcie-phy",
-};
-
-/* pcie1 phy */
-static struct omap_hwmod dra7xx_pcie1_phy_hwmod = {
-       .name           = "pcie1-phy",
-       .class          = &dra7xx_pcie_phy_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
-       .main_clk       = "l4_root_clk_div",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = DRA7XX_CM_L3INIT_PCIESS1_CLKCTRL_OFFSET,
@@ -1522,11 +1485,11 @@ static struct omap_hwmod dra7xx_pcie1_phy_hwmod = {
        },
 };
 
-/* pcie2 phy */
-static struct omap_hwmod dra7xx_pcie2_phy_hwmod = {
-       .name           = "pcie2-phy",
-       .class          = &dra7xx_pcie_phy_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
+/* pcie2 */
+static struct omap_hwmod dra7xx_pciess2_hwmod = {
+       .name           = "pcie2",
+       .class          = &dra7xx_pciess_hwmod_class,
+       .clkdm_name     = "pcie_clkdm",
        .main_clk       = "l4_root_clk_div",
        .prcm = {
                .omap4 = {
@@ -2877,50 +2840,34 @@ static struct omap_hwmod_ocp_if dra7xx_l4_cfg__ocp2scp3 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_1 -> pcie1 */
-static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pcie1 = {
+/* l3_main_1 -> pciess1 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pciess1 = {
        .master         = &dra7xx_l3_main_1_hwmod,
-       .slave          = &dra7xx_pcie1_hwmod,
+       .slave          = &dra7xx_pciess1_hwmod,
        .clk            = "l3_iclk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> pcie1 */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie1 = {
+/* l4_cfg -> pciess1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pciess1 = {
        .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie1_hwmod,
+       .slave          = &dra7xx_pciess1_hwmod,
        .clk            = "l4_root_clk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l3_main_1 -> pcie2 */
-static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pcie2 = {
+/* l3_main_1 -> pciess2 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__pciess2 = {
        .master         = &dra7xx_l3_main_1_hwmod,
-       .slave          = &dra7xx_pcie2_hwmod,
+       .slave          = &dra7xx_pciess2_hwmod,
        .clk            = "l3_iclk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_cfg -> pcie2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie2 = {
-       .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie2_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg -> pcie1 phy */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie1_phy = {
-       .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie1_phy_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg -> pcie2 phy */
-static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pcie2_phy = {
+/* l4_cfg -> pciess2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__pciess2 = {
        .master         = &dra7xx_l4_cfg_hwmod,
-       .slave          = &dra7xx_pcie2_phy_hwmod,
+       .slave          = &dra7xx_pciess2_hwmod,
        .clk            = "l4_root_clk_div",
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
@@ -3327,12 +3274,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_cfg__mpu,
        &dra7xx_l4_cfg__ocp2scp1,
        &dra7xx_l4_cfg__ocp2scp3,
-       &dra7xx_l3_main_1__pcie1,
-       &dra7xx_l4_cfg__pcie1,
-       &dra7xx_l3_main_1__pcie2,
-       &dra7xx_l4_cfg__pcie2,
-       &dra7xx_l4_cfg__pcie1_phy,
-       &dra7xx_l4_cfg__pcie2_phy,
+       &dra7xx_l3_main_1__pciess1,
+       &dra7xx_l4_cfg__pciess1,
+       &dra7xx_l3_main_1__pciess2,
+       &dra7xx_l4_cfg__pciess2,
        &dra7xx_l3_main_1__qspi,
        &dra7xx_l4_per3__rtcss,
        &dra7xx_l4_cfg__sata,
index 190fa43e74796809e47b73a9a84e8b6aa589aead..e642b079e9f313ac97876e8f74a8b10612a80b83 100644 (file)
@@ -173,6 +173,7 @@ static void __init omap3_igep0030_rev_g_legacy_init(void)
 
 static void __init omap3_evm_legacy_init(void)
 {
+       hsmmc2_internal_input_clk();
        legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 149);
 }
 
index a08a617a6c110365cf20ce9c5df54edef19c20c5..d6d6bc39e05c962d80b3b777b50c1d802764af0b 100644 (file)
@@ -252,10 +252,10 @@ static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
 {
        saved_mask[0] =
                omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
-                                       OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
+                                       OMAP4_PRM_IRQENABLE_MPU_OFFSET);
        saved_mask[1] =
                omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
-                                       OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET);
+                                       OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 
        omap4_prm_write_inst_reg(0, OMAP4430_PRM_OCP_SOCKET_INST,
                                 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
index 343c4e3a7c5d1aceb136a196dcae946a7c8f5a69..f6d02e4cbcda4e06954c1c960a54b945e28fe58b 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/platform_data/video-pxafb.h>
 #include <mach/bitfield.h>
 #include <linux/platform_data/mmc-pxamci.h>
+#include <linux/smc91x.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -81,11 +82,16 @@ static struct resource smc91x_resources[] = {
        }
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_32BIT | SMC91X_USE_DMA | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static void idp_backlight_power(int on)
index 0eecd83c624e3d98573d542efb834e7371cffc00..89a7c06570d3adf248a00bf07c3c3aff631d23cf 100644 (file)
@@ -11,6 +11,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
+#include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -40,7 +41,6 @@
 #define ICHP_VAL_IRQ           (1 << 31)
 #define ICHP_IRQ(i)            (((i) >> 16) & 0x7fff)
 #define IPR_VALID              (1 << 31)
-#define IRQ_BIT(n)             (((n) - PXA_IRQ(0)) & 0x1f)
 
 #define MAX_INTERNAL_IRQS      128
 
@@ -51,6 +51,7 @@
 static void __iomem *pxa_irq_base;
 static int pxa_internal_irq_nr;
 static bool cpu_has_ipr;
+static struct irq_domain *pxa_irq_domain;
 
 static inline void __iomem *irq_base(int i)
 {
@@ -66,18 +67,20 @@ static inline void __iomem *irq_base(int i)
 void pxa_mask_irq(struct irq_data *d)
 {
        void __iomem *base = irq_data_get_irq_chip_data(d);
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        uint32_t icmr = __raw_readl(base + ICMR);
 
-       icmr &= ~(1 << IRQ_BIT(d->irq));
+       icmr &= ~BIT(irq & 0x1f);
        __raw_writel(icmr, base + ICMR);
 }
 
 void pxa_unmask_irq(struct irq_data *d)
 {
        void __iomem *base = irq_data_get_irq_chip_data(d);
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        uint32_t icmr = __raw_readl(base + ICMR);
 
-       icmr |= 1 << IRQ_BIT(d->irq);
+       icmr |= BIT(irq & 0x1f);
        __raw_writel(icmr, base + ICMR);
 }
 
@@ -118,40 +121,63 @@ asmlinkage void __exception_irq_entry ichp_handle_irq(struct pt_regs *regs)
        } while (1);
 }
 
-void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
+static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
+                      irq_hw_number_t hw)
 {
-       int irq, i, n;
+       void __iomem *base = irq_base(hw / 32);
 
-       BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
+       /* initialize interrupt priority */
+       if (cpu_has_ipr)
+               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
+
+       irq_set_chip_and_handler(virq, &pxa_internal_irq_chip,
+                                handle_level_irq);
+       irq_set_chip_data(virq, base);
+       set_irq_flags(virq, IRQF_VALID);
+
+       return 0;
+}
+
+static struct irq_domain_ops pxa_irq_ops = {
+       .map    = pxa_irq_map,
+       .xlate  = irq_domain_xlate_onecell,
+};
+
+static __init void
+pxa_init_irq_common(struct device_node *node, int irq_nr,
+                   int (*fn)(struct irq_data *, unsigned int))
+{
+       int n;
 
        pxa_internal_irq_nr = irq_nr;
-       cpu_has_ipr = !cpu_is_pxa25x();
-       pxa_irq_base = io_p2v(0x40d00000);
+       pxa_irq_domain = irq_domain_add_legacy(node, irq_nr,
+                                              PXA_IRQ(0), 0,
+                                              &pxa_irq_ops, NULL);
+       if (!pxa_irq_domain)
+               panic("Unable to add PXA IRQ domain\n");
+       irq_set_default_host(pxa_irq_domain);
 
        for (n = 0; n < irq_nr; n += 32) {
                void __iomem *base = irq_base(n >> 5);
 
                __raw_writel(0, base + ICMR);   /* disable all IRQs */
                __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
-               for (i = n; (i < (n + 32)) && (i < irq_nr); i++) {
-                       /* initialize interrupt priority */
-                       if (cpu_has_ipr)
-                               __raw_writel(i | IPR_VALID, pxa_irq_base + IPR(i));
-
-                       irq = PXA_IRQ(i);
-                       irq_set_chip_and_handler(irq, &pxa_internal_irq_chip,
-                                                handle_level_irq);
-                       irq_set_chip_data(irq, base);
-                       set_irq_flags(irq, IRQF_VALID);
-               }
        }
-
        /* only unmasked interrupts kick us out of idle */
        __raw_writel(1, irq_base(0) + ICCR);
 
        pxa_internal_irq_chip.irq_set_wake = fn;
 }
 
+void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
+{
+       BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
+
+       pxa_irq_base = io_p2v(0x40d00000);
+       cpu_has_ipr = !cpu_is_pxa25x();
+       pxa_init_irq_common(NULL, irq_nr, fn);
+}
+
 #ifdef CONFIG_PM
 static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
 static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
@@ -203,30 +229,6 @@ struct syscore_ops pxa_irq_syscore_ops = {
 };
 
 #ifdef CONFIG_OF
-static struct irq_domain *pxa_irq_domain;
-
-static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
-                      irq_hw_number_t hw)
-{
-       void __iomem *base = irq_base(hw / 32);
-
-       /* initialize interrupt priority */
-       if (cpu_has_ipr)
-               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
-
-       irq_set_chip_and_handler(hw, &pxa_internal_irq_chip,
-                                handle_level_irq);
-       irq_set_chip_data(hw, base);
-       set_irq_flags(hw, IRQF_VALID);
-
-       return 0;
-}
-
-static struct irq_domain_ops pxa_irq_ops = {
-       .map    = pxa_irq_map,
-       .xlate  = irq_domain_xlate_onecell,
-};
-
 static const struct of_device_id intc_ids[] __initconst = {
        { .compatible = "marvell,pxa-intc", },
        {}
@@ -236,7 +238,7 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
 {
        struct device_node *node;
        struct resource res;
-       int n, ret;
+       int ret;
 
        node = of_find_matching_node(NULL, intc_ids);
        if (!node) {
@@ -267,23 +269,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
                return;
        }
 
-       pxa_irq_domain = irq_domain_add_legacy(node, pxa_internal_irq_nr, 0, 0,
-                                              &pxa_irq_ops, NULL);
-       if (!pxa_irq_domain)
-               panic("Unable to add PXA IRQ domain\n");
-
-       irq_set_default_host(pxa_irq_domain);
-
-       for (n = 0; n < pxa_internal_irq_nr; n += 32) {
-               void __iomem *base = irq_base(n >> 5);
-
-               __raw_writel(0, base + ICMR);   /* disable all IRQs */
-               __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
-       }
-
-       /* only unmasked interrupts kick us out of idle */
-       __raw_writel(1, irq_base(0) + ICCR);
-
-       pxa_internal_irq_chip.irq_set_wake = fn;
+       pxa_init_irq_common(node, pxa_internal_irq_nr, fn);
 }
 #endif /* CONFIG_OF */
index ad777b353bd5234797d93031ab6815747b65e363..eaee2c20b18956863557e0aba66e24f09e3f5070 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/pwm_backlight.h>
+#include <linux/smc91x.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -189,15 +190,20 @@ static struct resource smc91x_resources[] = {
        [1] = {
                .start  = LPD270_ETHERNET_IRQ,
                .end    = LPD270_ETHERNET_IRQ,
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
 };
 
+struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev.platform_data = &smc91x_platdata,
 };
 
 static struct resource lpd270_flash_resources[] = {
index 205f9bf3821e30236d579021f09d1157a6c3fee5..ac2ae5c71ab45b7428440ee8925b121533ba9509 100644 (file)
@@ -412,7 +412,7 @@ static struct fixed_voltage_config can_regulator_pdata = {
 };
 
 static struct platform_device can_regulator_device = {
-       .name   = "reg-fixed-volage",
+       .name   = "reg-fixed-voltage",
        .id     = 0,
        .dev    = {
                .platform_data  = &can_regulator_pdata,
index 850e506926dfb8adbc137f652353d8d84cc40197..c309593abdb223e9c9499c0469f080344ea40fd7 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/platform_data/video-clcd-versatile.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/smc91x.h>
 #include <linux/ata_platform.h>
 #include <linux/amba/mmci.h>
 #include <linux/gfp.h>
@@ -94,6 +95,10 @@ static struct smsc911x_platform_config smsc911x_config = {
        .phy_interface  = PHY_INTERFACE_MODE_MII,
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+};
+
 static struct platform_device realview_eth_device = {
        .name           = "smsc911x",
        .id             = 0,
@@ -107,6 +112,8 @@ int realview_eth_register(const char *name, struct resource *res)
        realview_eth_device.resource = res;
        if (strcmp(realview_eth_device.name, "smsc911x") == 0)
                realview_eth_device.dev.platform_data = &smsc911x_config;
+       else
+               realview_eth_device.dev.platform_data = &smc91x_platdata;
 
        return platform_device_register(&realview_eth_device);
 }
index 64c88d657f9efc6360600380910248a51fd3c73b..b3869cbbcc6858c5ddb6b8ab9808773cde4dfae6 100644 (file)
@@ -234,7 +234,7 @@ static struct resource realview_eb_eth_resources[] = {
        [1] = {
                .start          = IRQ_EB_ETH,
                .end            = IRQ_EB_ETH,
-               .flags          = IORESOURCE_IRQ,
+               .flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
 };
 
index 169262e3040dd77b25ae268bc39880929805f63c..af868d258e664b5a50a4c678506bf7da7ac6dfd0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pm.h>
 #include <linux/serial_core.h>
 #include <linux/slab.h>
+#include <linux/smc91x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
@@ -258,12 +259,17 @@ static int neponset_probe(struct platform_device *dev)
                        0x02000000, "smc91x-attrib"),
                { .flags = IORESOURCE_IRQ },
        };
+       struct smc91x_platdata smc91x_platdata = {
+               .flags = SMC91X_USE_8BIT | SMC91X_IO_SHIFT_2 | SMC91X_NOWAIT,
+       };
        struct platform_device_info smc91x_devinfo = {
                .parent = &dev->dev,
                .name = "smc91x",
                .id = 0,
                .res = smc91x_resources,
                .num_res = ARRAY_SIZE(smc91x_resources),
+               .data = &smc91x_platdata,
+               .size_data = sizeof(smc91x_platdata),
        };
        int ret, irq;
 
index 091261878effde2e56d1b4f81a157f7d696de765..1525d7b5f1b74b6d06ac1276a56a45c23781e060 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/mtd/partitions.h>
+#include <linux/smc91x.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -43,12 +44,18 @@ static struct resource smc91x_resources[] = {
 #endif
 };
 
+static struct smc91x_platdata smc91x_platdata = {
+       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+};
 
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
+       .dev = {
+               .platform_data  = &smc91x_platdata,
+       },
 };
 
 static struct platform_device *devices[] __initdata = {
index 483cb467bf65a13d1f414a88c0233b5e46e184d1..a0f3b1cd497cc70656637c6dd2215a07942c0b1e 100644 (file)
@@ -45,6 +45,6 @@ extern char secondary_trampoline, secondary_trampoline_end;
 
 extern unsigned long socfpga_cpu1start_addr;
 
-#define SOCFPGA_SCU_VIRT_BASE   0xfffec000
+#define SOCFPGA_SCU_VIRT_BASE   0xfee00000
 
 #endif
index 383d61e138af1e9dfeee1ccac39b6adb42f74236..f5e597c207b9e47d26c0a7d021563cc6bdc8bf35 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/cacheflush.h>
 
 #include "core.h"
 
@@ -73,6 +74,10 @@ void __init socfpga_sysmgr_init(void)
                        (u32 *) &socfpga_cpu1start_addr))
                pr_err("SMP: Need cpu1-start-addr in device tree.\n");
 
+       /* Ensure that socfpga_cpu1start_addr is visible to other CPUs */
+       smp_wmb();
+       sync_cache_w(&socfpga_cpu1start_addr);
+
        sys_manager_base_addr = of_iomap(np, 0);
 
        np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
index b067390cef4ed5c8432c77ab5ed4e7e78682bdcc..b373acade338ad7c64780da2f94bd3817b976f3e 100644 (file)
@@ -18,6 +18,7 @@ static const char *stih41x_dt_match[] __initdata = {
        "st,stih415",
        "st,stih416",
        "st,stih407",
+       "st,stih410",
        "st,stih418",
        NULL
 };
index a77604fbaf257acef8e2c546dd267a5e2ef501af..81502b90dd9130240bd716d4bfb866b9d5ac5efe 100644 (file)
@@ -1,10 +1,12 @@
 menuconfig ARCH_SUNXI
        bool "Allwinner SoCs" if ARCH_MULTI_V7
        select ARCH_REQUIRE_GPIOLIB
+       select ARCH_HAS_RESET_CONTROLLER
        select CLKSRC_MMIO
        select GENERIC_IRQ_CHIP
        select PINCTRL
        select SUN4I_TIMER
+       select RESET_CONTROLLER
 
 if ARCH_SUNXI
 
@@ -20,10 +22,8 @@ config MACH_SUN5I
 config MACH_SUN6I
        bool "Allwinner A31 (sun6i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select MFD_SUN6I_PRCM
-       select RESET_CONTROLLER
        select SUN5I_HSTIMER
 
 config MACH_SUN7I
@@ -37,16 +37,12 @@ config MACH_SUN7I
 config MACH_SUN8I
        bool "Allwinner A23 (sun8i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
        select MFD_SUN6I_PRCM
-       select RESET_CONTROLLER
 
 config MACH_SUN9I
        bool "Allwinner (sun9i) SoCs support"
        default ARCH_SUNXI
-       select ARCH_HAS_RESET_CONTROLLER
        select ARM_GIC
-       select RESET_CONTROLLER
 
 endif
index c6c7696b8db97e33344fdec64767d9409800cb06..8f15f70622a6aa30a9ff7f20fb6cea3a963fc53b 100644 (file)
@@ -1131,23 +1131,22 @@ static void __init l2c310_of_parse(const struct device_node *np,
        }
 
        ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K);
-       if (ret)
-               return;
-
-       switch (assoc) {
-       case 16:
-               *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
-               *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               break;
-       case 8:
-               *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
-               break;
-       default:
-               pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
-                      assoc);
-               break;
+       if (!ret) {
+               switch (assoc) {
+               case 16:
+                       *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
+                       *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       break;
+               case 8:
+                       *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
+                       break;
+               default:
+                       pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
+                              assoc);
+                       break;
+               }
        }
 
        prefetch = l2x0_saved_regs.prefetch_ctrl;
index 170a116d1b298c1befb81efdeaee49735362fd26..c27447653903f1134594fe309dc885285ea43bb3 100644 (file)
@@ -171,7 +171,7 @@ static int __dma_supported(struct device *dev, u64 mask, bool warn)
         */
        if (sizeof(mask) != sizeof(dma_addr_t) &&
            mask > (dma_addr_t)~0 &&
-           dma_to_pfn(dev, ~0) < max_pfn) {
+           dma_to_pfn(dev, ~0) < max_pfn - 1) {
                if (warn) {
                        dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
                                 mask);
index a982dc3190dfb3a841bbe196f76f58cdbb554f84..6333d9c178757fe4f365b8e765b2a9ea75e2b80b 100644 (file)
@@ -552,6 +552,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 
        pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
                inf->name, fsr, addr);
+       show_pte(current->mm, addr);
 
        info.si_signo = inf->sig;
        info.si_errno = 0;
index 004e35cdcfffea6fa4add161e7e4da0a17bf6a44..cf30daff8932504f95422c2aa3b5882b154713b5 100644 (file)
@@ -49,7 +49,10 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (!is_module_address(start) || !is_module_address(end - 1))
+       if (start < MODULES_VADDR || start >= MODULES_END)
+               return -EINVAL;
+
+       if (end < MODULES_VADDR || start >= MODULES_END)
                return -EINVAL;
 
        data.set_mask = set_mask;
index db10169a08de78980d0ad17b71224f96bbfb1d5c..8ca94d379bc35f2020dea0ea3e708b0fbb0bb827 100644 (file)
@@ -799,6 +799,7 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const struct of_device_id *match;
        const struct dmtimer_platform_data *pdata;
+       int ret;
 
        match = of_match_device(of_match_ptr(omap_timer_match), dev);
        pdata = match ? match->data : dev->platform_data;
@@ -860,7 +861,12 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        }
 
        if (!timer->reserved) {
-               pm_runtime_get_sync(dev);
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0) {
+                       dev_err(dev, "%s: pm_runtime_get_sync failed!\n",
+                               __func__);
+                       goto err_get_sync;
+               }
                __omap_dm_timer_init_regs(timer);
                pm_runtime_put(dev);
        }
@@ -873,6 +879,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        dev_dbg(dev, "Device Probed.\n");
 
        return 0;
+
+err_get_sync:
+       pm_runtime_put_noidle(dev);
+       pm_runtime_disable(dev);
+       return ret;
 }
 
 /**
@@ -899,6 +910,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
                }
        spin_unlock_irqrestore(&dm_timer_lock, flags);
 
+       pm_runtime_disable(&pdev->dev);
+
        return ret;
 }
 
index f1ad9c2ab2e917197f3a3a00d7b8b8499138e933..a857794432d6756ac628d55f362512ed375bcabd 100644 (file)
                };
 
                sgenet0: ethernet@1f210000 {
-                       compatible = "apm,xgene-enet";
+                       compatible = "apm,xgene1-sgenet";
                        status = "disabled";
                        reg = <0x0 0x1f210000 0x0 0xd100>,
                              <0x0 0x1f200000 0x0 0Xc300>,
                };
 
                xgenet: ethernet@1f610000 {
-                       compatible = "apm,xgene-enet";
+                       compatible = "apm,xgene1-xgenet";
                        status = "disabled";
                        reg = <0x0 0x1f610000 0x0 0xd100>,
                              <0x0 0x1f600000 0x0 0Xc300>,
index 27f32962e55c60f8b0e28407f12746513473926f..4eac8dcea423e2ff50b0101555fa475507769c91 100644 (file)
@@ -34,6 +34,7 @@
                        reg = <0x0 0x0>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@1 {
                        device_type = "cpu";
@@ -41,6 +42,7 @@
                        reg = <0x0 0x1>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@2 {
                        device_type = "cpu";
@@ -48,6 +50,7 @@
                        reg = <0x0 0x2>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@3 {
                        device_type = "cpu";
                        reg = <0x0 0x3>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
                };
        };
 
index ea2b5666a16f5a3e6b194559e21fc2538f58b7f0..c9b89efe0f562a9dd7cd1a60126f42cb8948ff23 100644 (file)
@@ -8,7 +8,7 @@
  */
 
        /* SoC fixed clocks */
-       soc_uartclk: refclk72738khz {
+       soc_uartclk: refclk7273800hz {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <7273800>;
index d429129ecb3d03fe3a7460ecd3ed9d02950cb193..133ee59de2d70672db3ca648952006cdfae7c7cb 100644 (file)
@@ -39,6 +39,7 @@
                        reg = <0x0 0x0>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A57_L2>;
                };
 
                A57_1: cpu@1 {
@@ -46,6 +47,7 @@
                        reg = <0x0 0x1>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A57_L2>;
                };
 
                A53_0: cpu@100 {
@@ -53,6 +55,7 @@
                        reg = <0x0 0x100>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_1: cpu@101 {
@@ -60,6 +63,7 @@
                        reg = <0x0 0x101>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_2: cpu@102 {
@@ -67,6 +71,7 @@
                        reg = <0x0 0x102>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
                };
 
                A53_3: cpu@103 {
                        reg = <0x0 0x103>;
                        device_type = "cpu";
                        enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
+               };
+
+               A57_L2: l2-cache0 {
+                       compatible = "cache";
+               };
+
+               A53_L2: l2-cache1 {
+                       compatible = "cache";
                };
        };
 
index efc59b3baf63fb0eb374383a3eb9ebbd73dcbdb8..20addabbd127c89acf70399c5605dfedccb55203 100644 (file)
@@ -37,6 +37,7 @@
                        reg = <0x0 0x0>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@1 {
                        device_type = "cpu";
@@ -44,6 +45,7 @@
                        reg = <0x0 0x1>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@2 {
                        device_type = "cpu";
@@ -51,6 +53,7 @@
                        reg = <0x0 0x2>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
                };
                cpu@3 {
                        device_type = "cpu";
                        reg = <0x0 0x3>;
                        enable-method = "spin-table";
                        cpu-release-addr = <0x0 0x8000fff8>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
                };
        };
 
index 5720608c50b1b7f969f881b8695a78742868f379..abb79b3cfcfea158cdcaa8ac1ffcbd32699da9b0 100644 (file)
@@ -29,7 +29,7 @@ aes-ce-blk-y := aes-glue-ce.o aes-ce.o
 obj-$(CONFIG_CRYPTO_AES_ARM64_NEON_BLK) += aes-neon-blk.o
 aes-neon-blk-y := aes-glue-neon.o aes-neon.o
 
-AFLAGS_aes-ce.o                := -DINTERLEAVE=2 -DINTERLEAVE_INLINE
+AFLAGS_aes-ce.o                := -DINTERLEAVE=4
 AFLAGS_aes-neon.o      := -DINTERLEAVE=4
 
 CFLAGS_aes-glue-ce.o   := -DUSE_V8_CRYPTO_EXTENSIONS
index 5901480bfdcaf1cd65aeb5b8ffd31c337ea73aed..750bac4e637e5323f29bd4859b6e655b3a035d95 100644 (file)
@@ -20,6 +20,9 @@
 #error "Only include this from assembly code"
 #endif
 
+#ifndef __ASM_ASSEMBLER_H
+#define __ASM_ASSEMBLER_H
+
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 
@@ -155,3 +158,5 @@ lr  .req    x30             // link register
 #endif
        orr     \rd, \lbits, \hbits, lsl #32
        .endm
+
+#endif /* __ASM_ASSEMBLER_H */
index cb9593079f29763c34f7e68fa89737355ac03adb..d8c25b7b18fbf42ddc66ab888fc22c530d752d15 100644 (file)
@@ -246,14 +246,30 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
        __ret; \
 })
 
-#define this_cpu_cmpxchg_1(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_2(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_4(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-#define this_cpu_cmpxchg_8(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
-
-#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
-       cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \
-                               o1, o2, n1, n2)
+#define _protect_cmpxchg_local(pcp, o, n)                      \
+({                                                             \
+       typeof(*raw_cpu_ptr(&(pcp))) __ret;                     \
+       preempt_disable();                                      \
+       __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n);       \
+       preempt_enable();                                       \
+       __ret;                                                  \
+})
+
+#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+
+#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2)          \
+({                                                                     \
+       int __ret;                                                      \
+       preempt_disable();                                              \
+       __ret = cmpxchg_double_local(   raw_cpu_ptr(&(ptr1)),           \
+                                       raw_cpu_ptr(&(ptr2)),           \
+                                       o1, o2, n1, n2);                \
+       preempt_enable();                                               \
+       __ret;                                                          \
+})
 
 #define cmpxchg64(ptr,o,n)             cmpxchg((ptr),(o),(n))
 #define cmpxchg64_local(ptr,o,n)       cmpxchg_local((ptr),(o),(n))
index 0710654631e789121f7b0d2247b485ebf585685a..c60643f14cda97e7ba6dd9676f10b133af4b0627 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_CPUIDLE_H
 #define __ASM_CPUIDLE_H
 
+#include <asm/proc-fns.h>
+
 #ifdef CONFIG_CPU_IDLE
 extern int cpu_init_idle(unsigned int cpu);
 extern int cpu_suspend(unsigned long arg);
index e2ff32a93b5cefc2c6fc2866d4d7befed27259fc..d2f49423c5dcbad70f63cbe777d522edbd41da75 100644 (file)
@@ -264,8 +264,10 @@ __AARCH64_INSN_FUNCS(ands, 0x7F200000, 0x6A000000)
 __AARCH64_INSN_FUNCS(bics,     0x7F200000, 0x6A200000)
 __AARCH64_INSN_FUNCS(b,                0xFC000000, 0x14000000)
 __AARCH64_INSN_FUNCS(bl,       0xFC000000, 0x94000000)
-__AARCH64_INSN_FUNCS(cbz,      0xFE000000, 0x34000000)
-__AARCH64_INSN_FUNCS(cbnz,     0xFE000000, 0x35000000)
+__AARCH64_INSN_FUNCS(cbz,      0x7F000000, 0x34000000)
+__AARCH64_INSN_FUNCS(cbnz,     0x7F000000, 0x35000000)
+__AARCH64_INSN_FUNCS(tbz,      0x7F000000, 0x36000000)
+__AARCH64_INSN_FUNCS(tbnz,     0x7F000000, 0x37000000)
 __AARCH64_INSN_FUNCS(bcond,    0xFF000010, 0x54000000)
 __AARCH64_INSN_FUNCS(svc,      0xFFE0001F, 0xD4000001)
 __AARCH64_INSN_FUNCS(hvc,      0xFFE0001F, 0xD4000002)
index 94674eb7e7bb3cebaf671ef28ec7de05145bb0c9..54bb4ba974417e269656d50adb524654851fbbd2 100644 (file)
  * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
  * not known to exist and will break with this configuration.
  *
+ * VTCR_EL2.PS is extracted from ID_AA64MMFR0_EL1.PARange at boot time
+ * (see hyp-init.S).
+ *
  * Note that when using 4K pages, we concatenate two first level page tables
  * together.
  *
 #ifdef CONFIG_ARM64_64K_PAGES
 /*
  * Stage2 translation configuration:
- * 40bits output (PS = 2)
  * 40bits input  (T0SZ = 24)
  * 64kB pages (TG0 = 1)
  * 2 level page tables (SL = 1)
 #else
 /*
  * Stage2 translation configuration:
- * 40bits output (PS = 2)
  * 40bits input  (T0SZ = 24)
  * 4kB pages (TG0 = 0)
  * 3 level page tables (SL = 1)
index 6458b53731421343e7640a922a202a2b4c9682be..bbfb600fa82295a8a81c85603254946422b70992 100644 (file)
@@ -158,6 +158,8 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define PTRS_PER_S2_PGD                (1 << PTRS_PER_S2_PGD_SHIFT)
 #define S2_PGD_ORDER           get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
 
+#define kvm_pgd_index(addr)    (((addr) >> PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1))
+
 /*
  * If we are concatenating first level stage-2 page tables, we would have less
  * than or equal to 16 pointers in the fake PGD, because that's what the
@@ -171,43 +173,6 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define KVM_PREALLOC_LEVEL     (0)
 #endif
 
-/**
- * kvm_prealloc_hwpgd - allocate inital table for VTTBR
- * @kvm:       The KVM struct pointer for the VM.
- * @pgd:       The kernel pseudo pgd
- *
- * When the kernel uses more levels of page tables than the guest, we allocate
- * a fake PGD and pre-populate it to point to the next-level page table, which
- * will be the real initial page table pointed to by the VTTBR.
- *
- * When KVM_PREALLOC_LEVEL==2, we allocate a single page for the PMD and
- * the kernel will use folded pud.  When KVM_PREALLOC_LEVEL==1, we
- * allocate 2 consecutive PUD pages.
- */
-static inline int kvm_prealloc_hwpgd(struct kvm *kvm, pgd_t *pgd)
-{
-       unsigned int i;
-       unsigned long hwpgd;
-
-       if (KVM_PREALLOC_LEVEL == 0)
-               return 0;
-
-       hwpgd = __get_free_pages(GFP_KERNEL | __GFP_ZERO, PTRS_PER_S2_PGD_SHIFT);
-       if (!hwpgd)
-               return -ENOMEM;
-
-       for (i = 0; i < PTRS_PER_S2_PGD; i++) {
-               if (KVM_PREALLOC_LEVEL == 1)
-                       pgd_populate(NULL, pgd + i,
-                                    (pud_t *)hwpgd + i * PTRS_PER_PUD);
-               else if (KVM_PREALLOC_LEVEL == 2)
-                       pud_populate(NULL, pud_offset(pgd, 0) + i,
-                                    (pmd_t *)hwpgd + i * PTRS_PER_PMD);
-       }
-
-       return 0;
-}
-
 static inline void *kvm_get_hwpgd(struct kvm *kvm)
 {
        pgd_t *pgd = kvm->arch.pgd;
@@ -224,12 +189,11 @@ static inline void *kvm_get_hwpgd(struct kvm *kvm)
        return pmd_offset(pud, 0);
 }
 
-static inline void kvm_free_hwpgd(struct kvm *kvm)
+static inline unsigned int kvm_get_hwpgd_size(void)
 {
-       if (KVM_PREALLOC_LEVEL > 0) {
-               unsigned long hwpgd = (unsigned long)kvm_get_hwpgd(kvm);
-               free_pages(hwpgd, PTRS_PER_S2_PGD_SHIFT);
-       }
+       if (KVM_PREALLOC_LEVEL > 0)
+               return PTRS_PER_S2_PGD * PAGE_SIZE;
+       return PTRS_PER_S2_PGD * sizeof(pgd_t);
 }
 
 static inline bool kvm_page_empty(void *ptr)
index a9eee33dfa62dc031ab8262c275eba79f8609bac..101a42bde728a8b9547bca989b696d473dcd7e42 100644 (file)
@@ -151,6 +151,15 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        unsigned int cpu = smp_processor_id();
 
+       /*
+        * init_mm.pgd does not contain any user mappings and it is always
+        * active for kernel addresses in TTBR1. Just set the reserved TTBR0.
+        */
+       if (next == &init_mm) {
+               cpu_set_reserved_ttbr0();
+               return;
+       }
+
        if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
                check_and_switch_context(next, tsk);
 }
index 09da25bc596fd0bdccdf03e94b37a4c81e0cc633..4fde8c1df97ffb46d9d2039a11cf574d05ed5a92 100644 (file)
@@ -204,25 +204,47 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
        return ret;
 }
 
+#define _percpu_read(pcp)                                              \
+({                                                                     \
+       typeof(pcp) __retval;                                           \
+       preempt_disable();                                              \
+       __retval = (typeof(pcp))__percpu_read(raw_cpu_ptr(&(pcp)),      \
+                                             sizeof(pcp));             \
+       preempt_enable();                                               \
+       __retval;                                                       \
+})
+
+#define _percpu_write(pcp, val)                                                \
+do {                                                                   \
+       preempt_disable();                                              \
+       __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val),       \
+                               sizeof(pcp));                           \
+       preempt_enable();                                               \
+} while(0)                                                             \
+
+#define _pcp_protect(operation, pcp, val)                      \
+({                                                             \
+       typeof(pcp) __retval;                                   \
+       preempt_disable();                                      \
+       __retval = (typeof(pcp))operation(raw_cpu_ptr(&(pcp)),  \
+                                         (val), sizeof(pcp));  \
+       preempt_enable();                                       \
+       __retval;                                               \
+})
+
 #define _percpu_add(pcp, val) \
-       __percpu_add(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+       _pcp_protect(__percpu_add, pcp, val)
 
-#define _percpu_add_return(pcp, val) (typeof(pcp)) (_percpu_add(pcp, val))
+#define _percpu_add_return(pcp, val) _percpu_add(pcp, val)
 
 #define _percpu_and(pcp, val) \
-       __percpu_and(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+       _pcp_protect(__percpu_and, pcp, val)
 
 #define _percpu_or(pcp, val) \
-       __percpu_or(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
-
-#define _percpu_read(pcp) (typeof(pcp))        \
-       (__percpu_read(raw_cpu_ptr(&(pcp)), sizeof(pcp)))
-
-#define _percpu_write(pcp, val) \
-       __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp))
+       _pcp_protect(__percpu_or, pcp, val)
 
 #define _percpu_xchg(pcp, val) (typeof(pcp)) \
-       (__percpu_xchg(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp)))
+       _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val))
 
 #define this_cpu_add_1(pcp, val) _percpu_add(pcp, val)
 #define this_cpu_add_2(pcp, val) _percpu_add(pcp, val)
index 16449c535e50fdcf358df430d67f38cce3893df3..800ec0e87ed955bbd38e93e448b19b6b4401625b 100644 (file)
@@ -460,7 +460,7 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
-                             PTE_PROT_NONE | PTE_VALID | PTE_WRITE;
+                             PTE_PROT_NONE | PTE_WRITE | PTE_TYPE_MASK;
        pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
        return pte;
 }
index 9a8fd84f8fb2b67fe4bc2d845e7f6b584cbf0799..941c375616e2072d3b9fbf6442426c3491f00c01 100644 (file)
@@ -39,7 +39,11 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
 
 #include <asm/memory.h>
 
-#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
+#define cpu_switch_mm(pgd,mm)                          \
+do {                                                   \
+       BUG_ON(pgd == swapper_pg_dir);                  \
+       cpu_do_switch_mm(virt_to_phys(pgd),mm);         \
+} while (0)
 
 #define cpu_get_pgd()                                  \
 ({                                                     \
index f9be30ea1cbd8bc5b00cf2627c2e0be47ab54d98..20e9591a60cff97c5ef3c93cbadab1aa1312fe09 100644 (file)
@@ -45,7 +45,8 @@
 #define STACK_TOP              STACK_TOP_MAX
 #endif /* CONFIG_COMPAT */
 
-#define ARCH_LOW_ADDRESS_LIMIT PHYS_MASK
+extern phys_addr_t arm64_dma_phys_limit;
+#define ARCH_LOW_ADDRESS_LIMIT (arm64_dma_phys_limit - 1)
 #endif /* __KERNEL__ */
 
 struct debug_info {
index c028fe37456feade18c0c5737cf974899a8b6ee4..53d9c354219f9737c4d6e47ee3d1123c8e9588ce 100644 (file)
@@ -48,6 +48,7 @@ static inline void tlb_flush(struct mmu_gather *tlb)
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        pgtable_page_dtor(pte);
        tlb_remove_entry(tlb, pte);
 }
@@ -56,6 +57,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
 static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        tlb_remove_entry(tlb, virt_to_page(pmdp));
 }
 #endif
@@ -64,6 +66,7 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
 static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp,
                                  unsigned long addr)
 {
+       __flush_tlb_pgtable(tlb->mm, addr);
        tlb_remove_entry(tlb, virt_to_page(pudp));
 }
 #endif
index 73f0ce570fb31caa23fe7da9b99edd68d4ef6679..c3bb05b98616789a4143bb6d48333cf818653ab2 100644 (file)
 #include <linux/sched.h>
 #include <asm/cputype.h>
 
-extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
-extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
-
-extern struct cpu_tlb_fns cpu_tlb;
-
 /*
  *     TLB Management
  *     ==============
@@ -148,6 +143,19 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
                flush_tlb_all();
 }
 
+/*
+ * Used to invalidate the TLB (walk caches) corresponding to intermediate page
+ * table levels (pgd/pud/pmd).
+ */
+static inline void __flush_tlb_pgtable(struct mm_struct *mm,
+                                      unsigned long uaddr)
+{
+       unsigned long addr = uaddr >> 12 | ((unsigned long)ASID(mm) << 48);
+
+       dsb(ishst);
+       asm("tlbi       vae1is, %0" : : "r" (addr));
+       dsb(ish);
+}
 /*
  * On AArch64, the cache coherency is handled via the set_pte_at() function.
  */
index bef04afd603190135972256e52981b0889b047bf..5ee07eee80c2b0c1f5ba2b1292420eb396103be0 100644 (file)
@@ -15,8 +15,9 @@ CFLAGS_REMOVE_return_address.o = -pg
 arm64-obj-y            := cputable.o debug-monitors.o entry.o irq.o fpsimd.o   \
                           entry-fpsimd.o process.o ptrace.o setup.o signal.o   \
                           sys.o stacktrace.o time.o traps.o io.o vdso.o        \
-                          hyp-stub.o psci.o cpu_ops.o insn.o return_address.o  \
-                          cpuinfo.o cpu_errata.o alternative.o cacheinfo.o
+                          hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o       \
+                          return_address.o cpuinfo.o cpu_errata.o              \
+                          alternative.o cacheinfo.o
 
 arm64-obj-$(CONFIG_COMPAT)             += sys32.o kuser32.o signal32.o         \
                                           sys_compat.o entry32.o               \
index b42c7b480e1ee3da6f3e0896480c7888668bfe1d..ab21e0d58278825e5dfc0199cd18b853f07232c1 100644 (file)
@@ -337,7 +337,11 @@ core_initcall(arm64_dmi_init);
 
 static void efi_set_pgd(struct mm_struct *mm)
 {
-       cpu_switch_mm(mm->pgd, mm);
+       if (mm == &init_mm)
+               cpu_set_reserved_ttbr0();
+       else
+               cpu_switch_mm(mm->pgd, mm);
+
        flush_tlb_all();
        if (icache_is_aivivt())
                __flush_icache_all();
@@ -354,3 +358,12 @@ void efi_virtmap_unload(void)
        efi_set_pgd(current->active_mm);
        preempt_enable();
 }
+
+/*
+ * UpdateCapsule() depends on the system being shutdown via
+ * ResetSystem().
+ */
+bool efi_poweroff_required(void)
+{
+       return efi_enabled(EFI_RUNTIME_SERVICES);
+}
index cf8556ae09d04ad0c81855870aa052cef746f8e7..c851be795080336938f4826cc0608234b0e34bfa 100644 (file)
@@ -156,7 +156,7 @@ static int ftrace_modify_graph_caller(bool enable)
 
        branch = aarch64_insn_gen_branch_imm(pc,
                                             (unsigned long)ftrace_graph_caller,
-                                            AARCH64_INSN_BRANCH_LINK);
+                                            AARCH64_INSN_BRANCH_NOLINK);
        nop = aarch64_insn_gen_nop();
 
        if (enable)
index 8ce88e08c030e16b90d2772d377160a12465fce2..07f930540f4a8b96b520cb630226ce700f79e732 100644 (file)
@@ -585,8 +585,8 @@ ENDPROC(set_cpu_boot_mode_flag)
  * zeroing of .bss would clobber it.
  */
        .pushsection    .data..cacheline_aligned
-ENTRY(__boot_cpu_mode)
        .align  L1_CACHE_SHIFT
+ENTRY(__boot_cpu_mode)
        .long   BOOT_CPU_MODE_EL2
        .long   0
        .popsection
index 27d4864577e5d47cca67f626ea3638b9f3f8b4ec..c8eca88f12e6b2702df24bc758ac99815226827c 100644 (file)
@@ -87,8 +87,10 @@ static void __kprobes *patch_map(void *addr, int fixmap)
 
        if (module && IS_ENABLED(CONFIG_DEBUG_SET_MODULE_RONX))
                page = vmalloc_to_page(addr);
-       else
+       else if (!module && IS_ENABLED(CONFIG_DEBUG_RODATA))
                page = virt_to_page(addr);
+       else
+               return addr;
 
        BUG_ON(!page);
        set_fixmap(fixmap, page_to_phys(page));
index fde9923af859c5764110b1accf7a9da567559dd4..c6b1f3b96f4581f329a11805118797afa9556e1d 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdarg.h>
 
 #include <linux/compat.h>
+#include <linux/efi.h>
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -150,6 +151,13 @@ void machine_restart(char *cmd)
        local_irq_disable();
        smp_send_stop();
 
+       /*
+        * UpdateCapsule() depends on the system being reset via
+        * ResetSystem().
+        */
+       if (efi_enabled(EFI_RUNTIME_SERVICES))
+               efi_reboot(reboot_mode, NULL);
+
        /* Now call the architecture specific reboot code. */
        if (arm_pm_restart)
                arm_pm_restart(reboot_mode, cmd);
diff --git a/arch/arm64/kernel/psci-call.S b/arch/arm64/kernel/psci-call.S
new file mode 100644 (file)
index 0000000..cf83e61
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/linkage.h>
+
+/* int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
+ENTRY(__invoke_psci_fn_hvc)
+       hvc     #0
+       ret
+ENDPROC(__invoke_psci_fn_hvc)
+
+/* int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
+ENTRY(__invoke_psci_fn_smc)
+       smc     #0
+       ret
+ENDPROC(__invoke_psci_fn_smc)
index 3425f311c49ed99588998d3a9b42e035bf592d84..9b8a70ae64a187d2647a10576a789ebba213788c 100644 (file)
@@ -57,6 +57,9 @@ static struct psci_operations psci_ops;
 static int (*invoke_psci_fn)(u64, u64, u64, u64);
 typedef int (*psci_initcall_t)(const struct device_node *);
 
+asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64);
+asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64);
+
 enum psci_function {
        PSCI_FN_CPU_SUSPEND,
        PSCI_FN_CPU_ON,
@@ -109,40 +112,6 @@ static void psci_power_state_unpack(u32 power_state,
                        PSCI_0_2_POWER_STATE_AFFL_SHIFT;
 }
 
-/*
- * The following two functions are invoked via the invoke_psci_fn pointer
- * and will not be inlined, allowing us to piggyback on the AAPCS.
- */
-static noinline int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1,
-                                        u64 arg2)
-{
-       asm volatile(
-                       __asmeq("%0", "x0")
-                       __asmeq("%1", "x1")
-                       __asmeq("%2", "x2")
-                       __asmeq("%3", "x3")
-                       "hvc    #0\n"
-               : "+r" (function_id)
-               : "r" (arg0), "r" (arg1), "r" (arg2));
-
-       return function_id;
-}
-
-static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
-                                        u64 arg2)
-{
-       asm volatile(
-                       __asmeq("%0", "x0")
-                       __asmeq("%1", "x1")
-                       __asmeq("%2", "x2")
-                       __asmeq("%3", "x3")
-                       "smc    #0\n"
-               : "+r" (function_id)
-               : "r" (arg0), "r" (arg1), "r" (arg2));
-
-       return function_id;
-}
-
 static int psci_get_version(void)
 {
        int err;
index c20a300e22137f741a236cb8385864b90fac9df4..d26fcd4cd6e6219cae5213b4b329d53d90a86a9b 100644 (file)
@@ -154,8 +154,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
        case __SI_TIMER:
                 err |= __put_user(from->si_tid, &to->si_tid);
                 err |= __put_user(from->si_overrun, &to->si_overrun);
-                err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr,
-                                  &to->si_ptr);
+                err |= __put_user(from->si_int, &to->si_int);
                break;
        case __SI_POLL:
                err |= __put_user(from->si_band, &to->si_band);
@@ -184,7 +183,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
        case __SI_MESGQ: /* But this is */
                err |= __put_user(from->si_pid, &to->si_pid);
                err |= __put_user(from->si_uid, &to->si_uid);
-               err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr);
+               err |= __put_user(from->si_int, &to->si_int);
                break;
        case __SI_SYS:
                err |= __put_user((compat_uptr_t)(unsigned long)
index fe652ffd34c28090076b8d8358c6e40f7d77034d..efa79e8d4196d01318779cd76f2e926c40765ae9 100644 (file)
@@ -174,8 +174,6 @@ ENDPROC(__kernel_clock_gettime)
 /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
 ENTRY(__kernel_clock_getres)
        .cfi_startproc
-       cbz     w1, 3f
-
        cmp     w0, #CLOCK_REALTIME
        ccmp    w0, #CLOCK_MONOTONIC, #0x4, ne
        b.ne    1f
@@ -188,6 +186,7 @@ ENTRY(__kernel_clock_getres)
        b.ne    4f
        ldr     x2, 6f
 2:
+       cbz     w1, 3f
        stp     xzr, x2, [x1]
 
 3:     /* res == NULL. */
index 0a24b9b8c6982ddc675bbbd40b7baaecc247f1f6..ef7d112f5ce0df9ca1c1a793301c2c1b3874e23f 100644 (file)
@@ -51,7 +51,7 @@ static int __init early_coherent_pool(char *p)
 }
 early_param("coherent_pool", early_coherent_pool);
 
-static void *__alloc_from_pool(size_t size, struct page **ret_page)
+static void *__alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
 {
        unsigned long val;
        void *ptr = NULL;
@@ -67,6 +67,8 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
 
                *ret_page = phys_to_page(phys);
                ptr = (void *)val;
+               if (flags & __GFP_ZERO)
+                       memset(ptr, 0, size);
        }
 
        return ptr;
@@ -101,6 +103,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                flags |= GFP_DMA;
        if (IS_ENABLED(CONFIG_DMA_CMA) && (flags & __GFP_WAIT)) {
                struct page *page;
+               void *addr;
 
                size = PAGE_ALIGN(size);
                page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
@@ -109,7 +112,10 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
                        return NULL;
 
                *dma_handle = phys_to_dma(dev, page_to_phys(page));
-               return page_address(page);
+               addr = page_address(page);
+               if (flags & __GFP_ZERO)
+                       memset(addr, 0, size);
+               return addr;
        } else {
                return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
        }
@@ -146,7 +152,7 @@ static void *__dma_alloc(struct device *dev, size_t size,
 
        if (!coherent && !(flags & __GFP_WAIT)) {
                struct page *page = NULL;
-               void *addr = __alloc_from_pool(size, &page);
+               void *addr = __alloc_from_pool(size, &page, flags);
 
                if (addr)
                        *dma_handle = phys_to_dma(dev, page_to_phys(page));
@@ -348,8 +354,6 @@ static struct dma_map_ops swiotlb_dma_ops = {
        .mapping_error = swiotlb_dma_mapping_error,
 };
 
-extern int swiotlb_late_init_with_default_size(size_t default_size);
-
 static int __init atomic_pool_init(void)
 {
        pgprot_t prot = __pgprot(PROT_NORMAL_NC);
@@ -411,21 +415,13 @@ out:
        return -ENOMEM;
 }
 
-static int __init swiotlb_late_init(void)
+static int __init arm64_dma_init(void)
 {
-       size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
+       int ret;
 
        dma_ops = &swiotlb_dma_ops;
 
-       return swiotlb_late_init_with_default_size(swiotlb_size);
-}
-
-static int __init arm64_dma_init(void)
-{
-       int ret = 0;
-
-       ret |= swiotlb_late_init();
-       ret |= atomic_pool_init();
+       ret = atomic_pool_init();
 
        return ret;
 }
index 71145f952070ebcd6067fcb49c5ad29e5c2ec11f..ae85da6307bb921e286bb7a99a218cab5dbe137e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dma-contiguous.h>
 #include <linux/efi.h>
+#include <linux/swiotlb.h>
 
 #include <asm/fixmap.h>
 #include <asm/memory.h>
@@ -45,6 +46,7 @@
 #include "mm.h"
 
 phys_addr_t memstart_addr __read_mostly = 0;
+phys_addr_t arm64_dma_phys_limit __read_mostly;
 
 #ifdef CONFIG_BLK_DEV_INITRD
 static int __init early_initrd(char *p)
@@ -85,7 +87,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 
        /* 4GB maximum for 32-bit only capable devices */
        if (IS_ENABLED(CONFIG_ZONE_DMA)) {
-               max_dma = PFN_DOWN(max_zone_dma_phys());
+               max_dma = PFN_DOWN(arm64_dma_phys_limit);
                zone_size[ZONE_DMA] = max_dma - min;
        }
        zone_size[ZONE_NORMAL] = max - max_dma;
@@ -156,8 +158,6 @@ early_param("mem", early_mem);
 
 void __init arm64_memblock_init(void)
 {
-       phys_addr_t dma_phys_limit = 0;
-
        memblock_enforce_memory_limit(memory_limit);
 
        /*
@@ -174,8 +174,10 @@ void __init arm64_memblock_init(void)
 
        /* 4GB maximum for 32-bit only capable devices */
        if (IS_ENABLED(CONFIG_ZONE_DMA))
-               dma_phys_limit = max_zone_dma_phys();
-       dma_contiguous_reserve(dma_phys_limit);
+               arm64_dma_phys_limit = max_zone_dma_phys();
+       else
+               arm64_dma_phys_limit = PHYS_MASK + 1;
+       dma_contiguous_reserve(arm64_dma_phys_limit);
 
        memblock_allow_resize();
        memblock_dump_all();
@@ -276,6 +278,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       swiotlb_init(1);
+
        set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
index bb0ea94c4ba1a563383f92f0f6f212c770b82d23..1d3ec3ddd84b72e654819b7818d03cbaf082815e 100644 (file)
@@ -51,7 +51,10 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (!is_module_address(start) || !is_module_address(end - 1))
+       if (start < MODULES_VADDR || start >= MODULES_END)
+               return -EINVAL;
+
+       if (end < MODULES_VADDR || end >= MODULES_END)
                return -EINVAL;
 
        data.set_mask = set_mask;
index 78d4483ba40c83fcd458fcda183c5b3d6a828267..ec4db6df5e0dde575278b3d11a6a90a2f5ffb224 100644 (file)
@@ -67,6 +67,11 @@ extern unsigned long empty_zero_page;
  */
 #define pgtable_cache_init()   do { } while (0)
 
+/*
+ * c6x is !MMU, so define the simpliest implementation
+ */
+#define pgprot_writecombine pgprot_noncached
+
 #include <asm-generic/pgtable.h>
 
 #endif /* _ASM_C6X_PGTABLE_H */
index 93bcf2abd1a15d4df394ed2a6b2d203dcbea620a..07d7a7ef8bd59c7387328e6add1b6426b0b51a52 100644 (file)
@@ -123,12 +123,14 @@ extern unsigned long empty_zero_page;
 #define PGDIR_MASK             (~(PGDIR_SIZE - 1))
 #define PTRS_PER_PGD           64
 
+#define __PAGETABLE_PUD_FOLDED
 #define PUD_SHIFT              26
 #define PTRS_PER_PUD           1
 #define PUD_SIZE               (1UL << PUD_SHIFT)
 #define PUD_MASK               (~(PUD_SIZE - 1))
 #define PUE_SIZE               256
 
+#define __PAGETABLE_PMD_FOLDED
 #define PMD_SHIFT              26
 #define PMD_SIZE               (1UL << PMD_SHIFT)
 #define PMD_MASK               (~(PMD_SIZE - 1))
index 8fd8ee70266a13cb61646b3b59530ee4181291cf..421e6ba3a173794d5a9cc8ba3b0465f2056a328f 100644 (file)
@@ -13,6 +13,7 @@
  * the M32R is two-level, so we don't really have any
  * PMD directory physically.
  */
+#define __PAGETABLE_PMD_FOLDED
 #define PMD_SHIFT      22
 #define PTRS_PER_PMD   1
 
index 28a145bfbb7151a567dd825026eac10f07845e74..35ed4a9981aefb627ed785ce311198c59000c396 100644 (file)
  */
 #ifdef CONFIG_SUN3
 #define PTRS_PER_PTE   16
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   2048
 #elif defined(CONFIG_COLDFIRE)
 #define PTRS_PER_PTE   512
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   1024
 #else
index 9359e504844258b12d2efd9c752859813210dd1a..d5779b0ec5730a01963a4a86940d1f5eb500084e 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_METAG_IO_H
 
 #include <linux/types.h>
+#include <asm/pgtable-bits.h>
 
 #define IO_SPACE_LIMIT  0
 
diff --git a/arch/metag/include/asm/pgtable-bits.h b/arch/metag/include/asm/pgtable-bits.h
new file mode 100644 (file)
index 0000000..25ba672
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Meta page table definitions.
+ */
+
+#ifndef _METAG_PGTABLE_BITS_H
+#define _METAG_PGTABLE_BITS_H
+
+#include <asm/metag_mem.h>
+
+/*
+ * Definitions for MMU descriptors
+ *
+ * These are the hardware bits in the MMCU pte entries.
+ * Derived from the Meta toolkit headers.
+ */
+#define _PAGE_PRESENT          MMCU_ENTRY_VAL_BIT
+#define _PAGE_WRITE            MMCU_ENTRY_WR_BIT
+#define _PAGE_PRIV             MMCU_ENTRY_PRIV_BIT
+/* Write combine bit - this can cause writes to occur out of order */
+#define _PAGE_WR_COMBINE       MMCU_ENTRY_WRC_BIT
+/* Sys coherent bit - this bit is never used by Linux */
+#define _PAGE_SYS_COHERENT     MMCU_ENTRY_SYS_BIT
+#define _PAGE_ALWAYS_ZERO_1    0x020
+#define _PAGE_CACHE_CTRL0      0x040
+#define _PAGE_CACHE_CTRL1      0x080
+#define _PAGE_ALWAYS_ZERO_2    0x100
+#define _PAGE_ALWAYS_ZERO_3    0x200
+#define _PAGE_ALWAYS_ZERO_4    0x400
+#define _PAGE_ALWAYS_ZERO_5    0x800
+
+/* These are software bits that we stuff into the gaps in the hardware
+ * pte entries that are not used.  Note, these DO get stored in the actual
+ * hardware, but the hardware just does not use them.
+ */
+#define _PAGE_ACCESSED         _PAGE_ALWAYS_ZERO_1
+#define _PAGE_DIRTY            _PAGE_ALWAYS_ZERO_2
+
+/* Pages owned, and protected by, the kernel. */
+#define _PAGE_KERNEL           _PAGE_PRIV
+
+/* No cacheing of this page */
+#define _PAGE_CACHE_WIN0       (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S)
+/* burst cacheing - good for data streaming */
+#define _PAGE_CACHE_WIN1       (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S)
+/* One cache way per thread */
+#define _PAGE_CACHE_WIN2       (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S)
+/* Full on cacheing */
+#define _PAGE_CACHE_WIN3       (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S)
+
+#define _PAGE_CACHEABLE                (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE)
+
+/* which bits are used for cache control ... */
+#define _PAGE_CACHE_MASK       (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \
+                                _PAGE_WR_COMBINE)
+
+/* This is a mask of the bits that pte_modify is allowed to change. */
+#define _PAGE_CHG_MASK         (PAGE_MASK)
+
+#define _PAGE_SZ_SHIFT         1
+#define _PAGE_SZ_4K            (0x0)
+#define _PAGE_SZ_8K            (0x1 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_16K           (0x2 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_32K           (0x3 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_64K           (0x4 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_128K          (0x5 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_256K          (0x6 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_512K          (0x7 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_1M            (0x8 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_2M            (0x9 << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_4M            (0xa << _PAGE_SZ_SHIFT)
+#define _PAGE_SZ_MASK          (0xf << _PAGE_SZ_SHIFT)
+
+#if defined(CONFIG_PAGE_SIZE_4K)
+#define _PAGE_SZ               (_PAGE_SZ_4K)
+#elif defined(CONFIG_PAGE_SIZE_8K)
+#define _PAGE_SZ               (_PAGE_SZ_8K)
+#elif defined(CONFIG_PAGE_SIZE_16K)
+#define _PAGE_SZ               (_PAGE_SZ_16K)
+#endif
+#define _PAGE_TABLE            (_PAGE_SZ | _PAGE_PRESENT)
+
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_8K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_16K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_32K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_64K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_128K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_256K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
+# define _PAGE_SZHUGE          (_PAGE_SZ_512K)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_1M)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_2M)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M)
+# define _PAGE_SZHUGE          (_PAGE_SZ_4M)
+#endif
+
+#endif /* _METAG_PGTABLE_BITS_H */
index d0604c0a87022231f37157531e1175894545ee4a..ffa3a3a2ecadda8bed7cf5e7b1508cd98c43abf8 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef _METAG_PGTABLE_H
 #define _METAG_PGTABLE_H
 
+#include <asm/pgtable-bits.h>
 #include <asm-generic/pgtable-nopmd.h>
 
 /* Invalid regions on Meta: 0x00000000-0x001FFFFF and 0xFFFF0000-0xFFFFFFFF */
 #define VMALLOC_END            0x7FFFFFFF
 #endif
 
-/*
- * Definitions for MMU descriptors
- *
- * These are the hardware bits in the MMCU pte entries.
- * Derived from the Meta toolkit headers.
- */
-#define _PAGE_PRESENT          MMCU_ENTRY_VAL_BIT
-#define _PAGE_WRITE            MMCU_ENTRY_WR_BIT
-#define _PAGE_PRIV             MMCU_ENTRY_PRIV_BIT
-/* Write combine bit - this can cause writes to occur out of order */
-#define _PAGE_WR_COMBINE       MMCU_ENTRY_WRC_BIT
-/* Sys coherent bit - this bit is never used by Linux */
-#define _PAGE_SYS_COHERENT     MMCU_ENTRY_SYS_BIT
-#define _PAGE_ALWAYS_ZERO_1    0x020
-#define _PAGE_CACHE_CTRL0      0x040
-#define _PAGE_CACHE_CTRL1      0x080
-#define _PAGE_ALWAYS_ZERO_2    0x100
-#define _PAGE_ALWAYS_ZERO_3    0x200
-#define _PAGE_ALWAYS_ZERO_4    0x400
-#define _PAGE_ALWAYS_ZERO_5    0x800
-
-/* These are software bits that we stuff into the gaps in the hardware
- * pte entries that are not used.  Note, these DO get stored in the actual
- * hardware, but the hardware just does not use them.
- */
-#define _PAGE_ACCESSED         _PAGE_ALWAYS_ZERO_1
-#define _PAGE_DIRTY            _PAGE_ALWAYS_ZERO_2
-
-/* Pages owned, and protected by, the kernel. */
-#define _PAGE_KERNEL           _PAGE_PRIV
-
-/* No cacheing of this page */
-#define _PAGE_CACHE_WIN0       (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S)
-/* burst cacheing - good for data streaming */
-#define _PAGE_CACHE_WIN1       (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S)
-/* One cache way per thread */
-#define _PAGE_CACHE_WIN2       (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S)
-/* Full on cacheing */
-#define _PAGE_CACHE_WIN3       (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S)
-
-#define _PAGE_CACHEABLE                (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE)
-
-/* which bits are used for cache control ... */
-#define _PAGE_CACHE_MASK       (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \
-                                _PAGE_WR_COMBINE)
-
-/* This is a mask of the bits that pte_modify is allowed to change. */
-#define _PAGE_CHG_MASK         (PAGE_MASK)
-
-#define _PAGE_SZ_SHIFT         1
-#define _PAGE_SZ_4K            (0x0)
-#define _PAGE_SZ_8K            (0x1 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_16K           (0x2 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_32K           (0x3 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_64K           (0x4 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_128K          (0x5 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_256K          (0x6 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_512K          (0x7 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_1M            (0x8 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_2M            (0x9 << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_4M            (0xa << _PAGE_SZ_SHIFT)
-#define _PAGE_SZ_MASK          (0xf << _PAGE_SZ_SHIFT)
-
-#if defined(CONFIG_PAGE_SIZE_4K)
-#define _PAGE_SZ               (_PAGE_SZ_4K)
-#elif defined(CONFIG_PAGE_SIZE_8K)
-#define _PAGE_SZ               (_PAGE_SZ_8K)
-#elif defined(CONFIG_PAGE_SIZE_16K)
-#define _PAGE_SZ               (_PAGE_SZ_16K)
-#endif
-#define _PAGE_TABLE            (_PAGE_SZ | _PAGE_PRESENT)
-
-#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_8K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_16K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_32K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_64K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_128K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_256K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
-# define _PAGE_SZHUGE          (_PAGE_SZ_512K)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_1M)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_2M)
-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M)
-# define _PAGE_SZHUGE          (_PAGE_SZ_4M)
-#endif
-
 /*
  * The Linux memory management assumes a three-level page table setup. On
  * Meta, we use that, but "fold" the mid level into the top-level page
index 881071c0794221475308604464cd7bd441b95945..13272fd5a5baec8e3b1a4de778a6982abf0adae7 100644 (file)
@@ -149,8 +149,8 @@ extern void exit_thread(void);
 
 unsigned long get_wchan(struct task_struct *p);
 
-#define        KSTK_EIP(tsk)   ((tsk)->thread.kernel_context->CurrPC)
-#define        KSTK_ESP(tsk)   ((tsk)->thread.kernel_context->AX[0].U0)
+#define        KSTK_EIP(tsk)   (task_pt_regs(tsk)->ctx.CurrPC)
+#define        KSTK_ESP(tsk)   (task_pt_regs(tsk)->ctx.AX[0].U0)
 
 #define user_stack_pointer(regs)        ((regs)->ctx.AX[0].U0)
 
index 0536bc021cc6c66667f0cbb66601c86b0ace9c10..ef548510b951b306d7b70cb941d08dc0dec3e4dd 100644 (file)
@@ -348,8 +348,9 @@ C_ENTRY(_user_exception):
  * The LP register should point to the location where the called function
  * should return.  [note that MAKE_SYS_CALL uses label 1] */
        /* See if the system call number is valid */
+       blti    r12, 5f
        addi    r11, r12, -__NR_syscalls;
-       bgei    r11,5f;
+       bgei    r11, 5f;
        /* Figure out which function to use for this system call.  */
        /* Note Microblaze barrel shift is optional, so don't rely on it */
        add     r12, r12, r12;                  /* convert num -> ptr */
@@ -375,7 +376,7 @@ C_ENTRY(_user_exception):
 
        /* The syscall number is invalid, return an error.  */
 5:
-       rtsd    r15, 8;         /* looks like a normal subroutine return */
+       braid   ret_from_trap
        addi    r3, r0, -ENOSYS;
 
 /* Entry point used to return from a syscall/trap */
@@ -411,7 +412,7 @@ C_ENTRY(ret_from_trap):
        bri     1b
 
        /* Maybe handle a signal */
-5:     
+5:
        andi    r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
        beqi    r11, 4f;                /* Signals to handle, handle them */
 
index bbcd82242059d36f91f2f4a7dfbd8d22fb479ea6..b6beb0e07b1b3b535f7625d61100e6c0087de00d 100644 (file)
@@ -216,6 +216,7 @@ int kvm_mips_host_tlb_write(struct kvm_vcpu *vcpu, unsigned long entryhi,
        if (idx > current_cpu_data.tlbsize) {
                kvm_err("%s: Invalid Index: %d\n", __func__, idx);
                kvm_mips_dump_host_tlbs();
+               local_irq_restore(flags);
                return -1;
        }
 
index c1388d40663b0143501bacae8af8f2793e54c815..bd6437f67dc03b01c3a76e57a53a811a61f0ebe7 100644 (file)
@@ -24,18 +24,18 @@ TRACE_EVENT(kvm_exit,
            TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
            TP_ARGS(vcpu, reason),
            TP_STRUCT__entry(
-                       __field(struct kvm_vcpu *, vcpu)
+                       __field(unsigned long, pc)
                        __field(unsigned int, reason)
            ),
 
            TP_fast_assign(
-                       __entry->vcpu = vcpu;
+                       __entry->pc = vcpu->arch.pc;
                        __entry->reason = reason;
            ),
 
            TP_printk("[%s]PC: 0x%08lx",
                      kvm_mips_exit_types_str[__entry->reason],
-                     __entry->vcpu->arch.pc)
+                     __entry->pc)
 );
 
 #endif /* _TRACE_KVM_H */
index afab728ab65ecde48b3c50c78e1dd19a795ad99d..96d3f9deb59c38b2172f7b3b7a81c1397ceebad9 100644 (file)
@@ -56,7 +56,9 @@ extern void paging_init(void);
 #define PGDIR_SHIFT    22
 #define PTRS_PER_PGD   1024
 #define PTRS_PER_PUD   1       /* we don't really have any PUD physically */
+#define __PAGETABLE_PUD_FOLDED
 #define PTRS_PER_PMD   1       /* we don't really have any PMD physically */
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PTE   1024
 
 #define PGD_SIZE       PAGE_SIZE
index 20fb1cf2dab63238b0e8b464a7b08a447257946e..64246214487288eb5cc352dd625b4e55538dded2 100644 (file)
 
 #include <uapi/asm/ptrace.h>
 
+/* This struct defines the way the registers are stored on the
+   stack during a system call.  */
+
 #ifndef __ASSEMBLY__
+struct pt_regs {
+       unsigned long  r8;      /* r8-r15 Caller-saved GP registers */
+       unsigned long  r9;
+       unsigned long  r10;
+       unsigned long  r11;
+       unsigned long  r12;
+       unsigned long  r13;
+       unsigned long  r14;
+       unsigned long  r15;
+       unsigned long  r1;      /* Assembler temporary */
+       unsigned long  r2;      /* Retval LS 32bits */
+       unsigned long  r3;      /* Retval MS 32bits */
+       unsigned long  r4;      /* r4-r7 Register arguments */
+       unsigned long  r5;
+       unsigned long  r6;
+       unsigned long  r7;
+       unsigned long  orig_r2; /* Copy of r2 ?? */
+       unsigned long  ra;      /* Return address */
+       unsigned long  fp;      /* Frame pointer */
+       unsigned long  sp;      /* Stack pointer */
+       unsigned long  gp;      /* Global pointer */
+       unsigned long  estatus;
+       unsigned long  ea;      /* Exception return address (pc) */
+       unsigned long  orig_r7;
+};
+
+/*
+ * This is the extended stack used by signal handlers and the context
+ * switcher: it's pushed after the normal "struct pt_regs".
+ */
+struct switch_stack {
+       unsigned long  r16;     /* r16-r23 Callee-saved GP registers */
+       unsigned long  r17;
+       unsigned long  r18;
+       unsigned long  r19;
+       unsigned long  r20;
+       unsigned long  r21;
+       unsigned long  r22;
+       unsigned long  r23;
+       unsigned long  fp;
+       unsigned long  gp;
+       unsigned long  ra;
+};
+
 #define user_mode(regs)        (((regs)->estatus & ESTATUS_EU))
 
 #define instruction_pointer(regs)      ((regs)->ra)
diff --git a/arch/nios2/include/asm/ucontext.h b/arch/nios2/include/asm/ucontext.h
deleted file mode 100644 (file)
index 2c87614..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
- * Copyright (C) 2004 Microtronix Datacom Ltd
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_NIOS2_UCONTEXT_H
-#define _ASM_NIOS2_UCONTEXT_H
-
-typedef int greg_t;
-#define NGREG 32
-typedef greg_t gregset_t[NGREG];
-
-struct mcontext {
-       int version;
-       gregset_t gregs;
-};
-
-#define MCONTEXT_VERSION 2
-
-struct ucontext {
-       unsigned long     uc_flags;
-       struct ucontext  *uc_link;
-       stack_t           uc_stack;
-       struct mcontext   uc_mcontext;
-       sigset_t          uc_sigmask;   /* mask last for extensibility */
-};
-
-#endif
index 4f07ca3f8d10edd443595bac553bb170f192ce58..e0bb972a50d7425b3f422605ab64bbc82c428cc0 100644 (file)
@@ -1,4 +1,5 @@
 include include/uapi/asm-generic/Kbuild.asm
 
 header-y += elf.h
-header-y += ucontext.h
+
+generic-y += ucontext.h
index a5b91ae5cf56fb5fcff4cfb6e3ad62bd96998491..6f06d3b2949e7ffd3d95c4951517a99abdcdeea1 100644 (file)
@@ -50,9 +50,7 @@
 
 typedef unsigned long elf_greg_t;
 
-#define ELF_NGREG      \
-       ((sizeof(struct pt_regs) + sizeof(struct switch_stack)) /       \
-               sizeof(elf_greg_t))
+#define ELF_NGREG              49
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 typedef unsigned long elf_fpregset_t;
index e83a7c9d1c36c4bc6a2690bfac8fc4a05f015cfa..71a330597adff689dcae092d63839aad1fb8b7d3 100644 (file)
 
 #define NUM_PTRACE_REG (PTR_TLBMISC + 1)
 
-/* this struct defines the way the registers are stored on the
-   stack during a system call.
-
-   There is a fake_regs in setup.c that has to match pt_regs.*/
-
-struct pt_regs {
-       unsigned long  r8;              /* r8-r15 Caller-saved GP registers */
-       unsigned long  r9;
-       unsigned long  r10;
-       unsigned long  r11;
-       unsigned long  r12;
-       unsigned long  r13;
-       unsigned long  r14;
-       unsigned long  r15;
-       unsigned long  r1;              /* Assembler temporary */
-       unsigned long  r2;              /* Retval LS 32bits */
-       unsigned long  r3;              /* Retval MS 32bits */
-       unsigned long  r4;              /* r4-r7 Register arguments */
-       unsigned long  r5;
-       unsigned long  r6;
-       unsigned long  r7;
-       unsigned long  orig_r2;         /* Copy of r2 ?? */
-       unsigned long  ra;              /* Return address */
-       unsigned long  fp;              /* Frame pointer */
-       unsigned long  sp;              /* Stack pointer */
-       unsigned long  gp;              /* Global pointer */
-       unsigned long  estatus;
-       unsigned long  ea;              /* Exception return address (pc) */
-       unsigned long  orig_r7;
-};
-
-/*
- * This is the extended stack used by signal handlers and the context
- * switcher: it's pushed after the normal "struct pt_regs".
- */
-struct switch_stack {
-       unsigned long  r16;             /* r16-r23 Callee-saved GP registers */
-       unsigned long  r17;
-       unsigned long  r18;
-       unsigned long  r19;
-       unsigned long  r20;
-       unsigned long  r21;
-       unsigned long  r22;
-       unsigned long  r23;
-       unsigned long  fp;
-       unsigned long  gp;
-       unsigned long  ra;
+/* User structures for general purpose registers.  */
+struct user_pt_regs {
+       __u32           regs[49];
 };
 
 #endif /* __ASSEMBLY__ */
index 7b8bb41867d4416e7b1cfeb61e1b930fc68c71dc..b67944a509273a020a8e13e9ebf0e039e492867c 100644 (file)
  * details.
  */
 
-#ifndef _ASM_NIOS2_SIGCONTEXT_H
-#define _ASM_NIOS2_SIGCONTEXT_H
+#ifndef _UAPI__ASM_SIGCONTEXT_H
+#define _UAPI__ASM_SIGCONTEXT_H
 
-#include <asm/ptrace.h>
+#include <linux/types.h>
+
+#define MCONTEXT_VERSION 2
 
 struct sigcontext {
-       struct pt_regs regs;
-       unsigned long  sc_mask; /* old sigmask */
+       int version;
+       unsigned long gregs[32];
 };
 
 #endif
index 2d0ea25be1717de06d8cd138032dc5c7c5f3970d..dda41e4fe7070885ee7ab77e4c5e9e18e51dd0a3 100644 (file)
@@ -39,7 +39,7 @@ static inline int rt_restore_ucontext(struct pt_regs *regs,
                                        struct ucontext *uc, int *pr2)
 {
        int temp;
-       greg_t *gregs = uc->uc_mcontext.gregs;
+       unsigned long *gregs = uc->uc_mcontext.gregs;
        int err;
 
        /* Always make any pending restarted system calls return -EINTR */
@@ -127,7 +127,7 @@ badframe:
 static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
 {
        struct switch_stack *sw = (struct switch_stack *)regs - 1;
-       greg_t *gregs = uc->uc_mcontext.gregs;
+       unsigned long *gregs = uc->uc_mcontext.gregs;
        int err = 0;
 
        err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
index 0d231adfe576b897073c924e02211dea7b110285..0c9b6afe69e9094815cc1e73084422368b3a2e52 100644 (file)
@@ -126,7 +126,6 @@ good_area:
                break;
        }
 
-survive:
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -220,11 +219,6 @@ no_context:
  */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_global_init(tsk)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
        if (!user_mode(regs))
                goto no_context;
        pagefault_out_of_memory();
index f213f5b4c4239b961e260c659447886a8646f0bd..d17437238a2cef75dd4d46593c760320933b6d38 100644 (file)
@@ -26,7 +26,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
        if (likely(pgd != NULL)) {
                memset(pgd, 0, PAGE_SIZE<<PGD_ALLOC_ORDER);
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
                actual_pgd += PTRS_PER_PGD;
                /* Populate first pmd with allocated memory.  We mark it
                 * with PxD_FLAG_ATTACHED as a signal to the system that this
@@ -45,7 +45,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
        pgd -= PTRS_PER_PGD;
 #endif
        free_pages((unsigned long)pgd, PGD_ALLOC_ORDER);
@@ -72,12 +72,15 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
-#ifdef CONFIG_64BIT
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
-               /* This is the permanent pmd attached to the pgd;
-                * cannot free it */
+               /*
+                * This is the permanent pmd attached to the pgd;
+                * cannot free it.
+                * Increment the counter to compensate for the decrement
+                * done by generic mm code.
+                */
+               mm_inc_nr_pmds(mm);
                return;
-#endif
        free_pages((unsigned long)pmd, PMD_ORDER);
 }
 
@@ -99,7 +102,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 static inline void
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
-#ifdef CONFIG_64BIT
+#if PT_NLEVELS == 3
        /* preserve the gateway marker if this is the beginning of
         * the permanent pmd */
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
index 8c966b2270aa6692c6f085027a8c70098b447733..15207b9362bfd0947064f7572ad34fdfb6e4d30c 100644 (file)
@@ -96,6 +96,7 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long);
 #if PT_NLEVELS == 3
 #define BITS_PER_PMD   (PAGE_SHIFT + PMD_ORDER - BITS_PER_PMD_ENTRY)
 #else
+#define __PAGETABLE_PMD_FOLDED
 #define BITS_PER_PMD   0
 #endif
 #define PTRS_PER_PMD    (1UL << BITS_PER_PMD)
index 5a8997d63899346a82e759f30b601eaf907bac37..8eefb12d1d33f3fc87195a0cd9efe0d0fd0301b2 100644 (file)
@@ -55,8 +55,8 @@
 #define ENTRY_COMP(_name_) .word sys_##_name_
 #endif
 
-       ENTRY_SAME(restart_syscall)     /* 0 */
-       ENTRY_SAME(exit)
+90:    ENTRY_SAME(restart_syscall)     /* 0 */
+91:    ENTRY_SAME(exit)
        ENTRY_SAME(fork_wrapper)
        ENTRY_SAME(read)
        ENTRY_SAME(write)
        ENTRY_SAME(bpf)
        ENTRY_COMP(execveat)
 
-       /* Nothing yet */
+
+.ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b))
+.error "size of syscall table does not fit value of __NR_Linux_syscalls"
+.endif
 
 #undef ENTRY_SAME
 #undef ENTRY_DIFF
index 2bf8e9307be9833b5bf9af51defdfada8feae68d..4c8ad592ae3351d96f7e225411d9f551657c5bc7 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 9cfa3706a1b8750942d7e41a91ef44996053a2ad..f1ea5972f6eccddceb7b776961ff67dcf2cb14e6 100644 (file)
@@ -113,6 +113,7 @@ extern void iommu_register_group(struct iommu_table *tbl,
                                 int pci_domain_number, unsigned long pe_num);
 extern int iommu_add_device(struct device *dev);
 extern void iommu_del_device(struct device *dev);
+extern int __init tce_iommu_bus_notifier_init(void);
 #else
 static inline void iommu_register_group(struct iommu_table *tbl,
                                        int pci_domain_number,
@@ -128,6 +129,11 @@ static inline int iommu_add_device(struct device *dev)
 static inline void iommu_del_device(struct device *dev)
 {
 }
+
+static inline int __init tce_iommu_bus_notifier_init(void)
+{
+        return 0;
+}
 #endif /* !CONFIG_IOMMU_API */
 
 static inline void set_iommu_table_base_and_group(struct device *dev,
diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h
new file mode 100644 (file)
index 0000000..744fd54
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _ASM_POWERPC_IRQ_WORK_H
+#define _ASM_POWERPC_IRQ_WORK_H
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+       return true;
+}
+
+#endif /* _ASM_POWERPC_IRQ_WORK_H */
index 03cd858a401c067b1b34f18e9b5fddd521e8fe2d..4cbe23af400ab622749b31f980d5d72d6b8587ac 100644 (file)
 #define PPC_INST_MFSPR_PVR_MASK                0xfc1fffff
 #define PPC_INST_MFTMR                 0x7c0002dc
 #define PPC_INST_MSGSND                        0x7c00019c
+#define PPC_INST_MSGCLR                        0x7c0001dc
 #define PPC_INST_MSGSNDP               0x7c00011c
 #define PPC_INST_MTTMR                 0x7c0003dc
 #define PPC_INST_NOP                   0x60000000
                                        ___PPC_RB(b) | __PPC_EH(eh))
 #define PPC_MSGSND(b)          stringify_in_c(.long PPC_INST_MSGSND | \
                                        ___PPC_RB(b))
+#define PPC_MSGCLR(b)          stringify_in_c(.long PPC_INST_MSGCLR | \
+                                       ___PPC_RB(b))
 #define PPC_MSGSNDP(b)         stringify_in_c(.long PPC_INST_MSGSNDP | \
                                        ___PPC_RB(b))
 #define PPC_POPCNTB(a, s)      stringify_in_c(.long PPC_INST_POPCNTB | \
index 1c874fb533bbf22fe8ff019b328ae623214243bb..af56b5c6c81ab18aefe24b16c810a3b89604434d 100644 (file)
 #define   SRR1_ISI_N_OR_G      0x10000000 /* ISI: Access is no-exec or G */
 #define   SRR1_ISI_PROT                0x08000000 /* ISI: Other protection fault */
 #define   SRR1_WAKEMASK                0x00380000 /* reason for wakeup */
+#define   SRR1_WAKEMASK_P8     0x003c0000 /* reason for wakeup on POWER8 */
 #define   SRR1_WAKESYSERR      0x00300000 /* System error */
 #define   SRR1_WAKEEE          0x00200000 /* External interrupt */
 #define   SRR1_WAKEMT          0x00280000 /* mtctrl */
 #define          SRR1_WAKEHMI          0x00280000 /* Hypervisor maintenance */
 #define   SRR1_WAKEDEC         0x00180000 /* Decrementer interrupt */
+#define   SRR1_WAKEDBELL       0x00140000 /* Privileged doorbell on P8 */
 #define   SRR1_WAKETHERM       0x00100000 /* Thermal management interrupt */
 #define          SRR1_WAKERESET        0x00100000 /* System reset */
+#define   SRR1_WAKEHDBELL      0x000c0000 /* Hypervisor doorbell on P8 */
 #define          SRR1_WAKESTATE        0x00030000 /* Powersave exit mask [46:47] */
 #define          SRR1_WS_DEEPEST       0x00030000 /* Some resources not maintained,
                                          * may not be recoverable */
index f337666768a76594b41b59f283efa3b891988193..f8304687833651975722e4f8aa51741fffad63d9 100644 (file)
@@ -437,6 +437,26 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
+       {       /* Power8NVL */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x004c0000,
+               .cpu_name               = "POWER8NVL (raw)",
+               .cpu_features           = CPU_FTRS_POWER8,
+               .cpu_user_features      = COMMON_USER_POWER8,
+               .cpu_user_features2     = COMMON_USER2_POWER8,
+               .mmu_features           = MMU_FTRS_POWER8,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_IBM,
+               .oprofile_cpu_type      = "ppc64/power8",
+               .oprofile_type          = PPC_OPROFILE_INVALID,
+               .cpu_setup              = __setup_cpu_power8,
+               .cpu_restore            = __restore_cpu_power8,
+               .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
+               .platform               = "power8",
+       },
        {       /* Power8 DD1: Does not support doorbell IPIs */
                .pvr_mask               = 0xffffff00,
                .pvr_value              = 0x004d0100,
index f4217819cc31fd417243d17f079c8bf2471d37a5..2128f3a96c32dd743908f286d4cf72d6d7701568 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/dbell.h>
 #include <asm/irq_regs.h>
+#include <asm/kvm_ppc.h>
 
 #ifdef CONFIG_SMP
 void doorbell_setup_this_cpu(void)
@@ -41,6 +42,7 @@ void doorbell_exception(struct pt_regs *regs)
 
        may_hard_irq_enable();
 
+       kvmppc_set_host_ipi(smp_processor_id(), 0);
        __this_cpu_inc(irq_stat.doorbell_irqs);
 
        smp_ipi_demux();
index c2df8150bd7a0425fc00ebcc78d784d6b280c146..9519e6bdc6d75c324334bf4f0f52dd6da9d9bbcc 100644 (file)
@@ -1408,7 +1408,7 @@ machine_check_handle_early:
        bne     9f                      /* continue in V mode if we are. */
 
 5:
-#ifdef CONFIG_KVM_BOOK3S_64_HV
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
        /*
         * We are coming from kernel context. Check if we are coming from
         * guest. if yes, then we can continue. We will fall through
index 5d3968c4d79973a4645f9d7b4069056311fd42cc..b054f33ab1fbcdad3bff7fda332c9e55dcda1d2f 100644 (file)
@@ -1175,4 +1175,30 @@ void iommu_del_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(iommu_del_device);
 
+static int tce_iommu_bus_notifier(struct notifier_block *nb,
+                unsigned long action, void *data)
+{
+        struct device *dev = data;
+
+        switch (action) {
+        case BUS_NOTIFY_ADD_DEVICE:
+                return iommu_add_device(dev);
+        case BUS_NOTIFY_DEL_DEVICE:
+                if (dev->iommu_group)
+                        iommu_del_device(dev);
+                return 0;
+        default:
+                return 0;
+        }
+}
+
+static struct notifier_block tce_iommu_bus_nb = {
+        .notifier_call = tce_iommu_bus_notifier,
+};
+
+int __init tce_iommu_bus_notifier_init(void)
+{
+        bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+        return 0;
+}
 #endif /* CONFIG_IOMMU_API */
index 6e19afa35a153d2736af94bc845008d724fe735f..ec9ec2058d2d3f3ec6db2dfbe25b35ab1f4cfb0b 100644 (file)
@@ -541,8 +541,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
        if (smp_ops->give_timebase)
                smp_ops->give_timebase();
 
-       /* Wait until cpu puts itself in the online map */
-       while (!cpu_online(cpu))
+       /* Wait until cpu puts itself in the online & active maps */
+       while (!cpu_online(cpu) || !cpu_active(cpu))
                cpu_relax();
 
        return 0;
index de4018a1bc4bd290ecd0e970bd51960b281497c3..de747563d29df39be580e6cd67c54769194dce42 100644 (file)
@@ -636,7 +636,7 @@ static int kvmppc_get_yield_count(struct kvm_vcpu *vcpu)
        spin_lock(&vcpu->arch.vpa_update_lock);
        lppaca = (struct lppaca *)vcpu->arch.vpa.pinned_addr;
        if (lppaca)
-               yield_count = lppaca->yield_count;
+               yield_count = be32_to_cpu(lppaca->yield_count);
        spin_unlock(&vcpu->arch.vpa_update_lock);
        return yield_count;
 }
@@ -942,20 +942,20 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,
 static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                bool preserve_top32)
 {
+       struct kvm *kvm = vcpu->kvm;
        struct kvmppc_vcore *vc = vcpu->arch.vcore;
        u64 mask;
 
+       mutex_lock(&kvm->lock);
        spin_lock(&vc->lock);
        /*
         * If ILE (interrupt little-endian) has changed, update the
         * MSR_LE bit in the intr_msr for each vcpu in this vcore.
         */
        if ((new_lpcr & LPCR_ILE) != (vc->lpcr & LPCR_ILE)) {
-               struct kvm *kvm = vcpu->kvm;
                struct kvm_vcpu *vcpu;
                int i;
 
-               mutex_lock(&kvm->lock);
                kvm_for_each_vcpu(i, vcpu, kvm) {
                        if (vcpu->arch.vcore != vc)
                                continue;
@@ -964,7 +964,6 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                        else
                                vcpu->arch.intr_msr &= ~MSR_LE;
                }
-               mutex_unlock(&kvm->lock);
        }
 
        /*
@@ -981,6 +980,7 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
                mask &= 0xFFFFFFFF;
        vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);
        spin_unlock(&vc->lock);
+       mutex_unlock(&kvm->lock);
 }
 
 static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
index bb94e6f20c813bbcdb8297d9fb860a538c5e4f08..6cbf1630cb70c9d8b306a7628c91a3c9acf35785 100644 (file)
@@ -1005,6 +1005,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        /* Save HEIR (HV emulation assist reg) in emul_inst
           if this is an HEI (HV emulation interrupt, e40) */
        li      r3,KVM_INST_FETCH_FAILED
+       stw     r3,VCPU_LAST_INST(r9)
        cmpwi   r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
        bne     11f
        mfspr   r3,SPRN_HEIR
index e69142f4af089cf986dd84f3fb2731ae705cf1f2..54323d6b5166218fa4e9c548a0511c7ec64884dd 100644 (file)
@@ -836,30 +836,4 @@ void __init pnv_pci_init(void)
 #endif
 }
 
-static int tce_iommu_bus_notifier(struct notifier_block *nb,
-               unsigned long action, void *data)
-{
-       struct device *dev = data;
-
-       switch (action) {
-       case BUS_NOTIFY_ADD_DEVICE:
-               return iommu_add_device(dev);
-       case BUS_NOTIFY_DEL_DEVICE:
-               if (dev->iommu_group)
-                       iommu_del_device(dev);
-               return 0;
-       default:
-               return 0;
-       }
-}
-
-static struct notifier_block tce_iommu_bus_nb = {
-       .notifier_call = tce_iommu_bus_notifier,
-};
-
-static int __init tce_iommu_bus_notifier_init(void)
-{
-       bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
-       return 0;
-}
 machine_subsys_initcall_sync(powernv, tce_iommu_bus_notifier_init);
index fc34025ef82270b00c7c32811dca20552a61d2fe..38a45088f633bb190ff53b5f7ac8306fd24acb4e 100644 (file)
@@ -33,6 +33,8 @@
 #include <asm/runlatch.h>
 #include <asm/code-patching.h>
 #include <asm/dbell.h>
+#include <asm/kvm_ppc.h>
+#include <asm/ppc-opcode.h>
 
 #include "powernv.h"
 
@@ -149,7 +151,7 @@ static int pnv_smp_cpu_disable(void)
 static void pnv_smp_cpu_kill_self(void)
 {
        unsigned int cpu;
-       unsigned long srr1;
+       unsigned long srr1, wmask;
        u32 idle_states;
 
        /* Standard hot unplug procedure */
@@ -161,6 +163,10 @@ static void pnv_smp_cpu_kill_self(void)
        generic_set_cpu_dead(cpu);
        smp_wmb();
 
+       wmask = SRR1_WAKEMASK;
+       if (cpu_has_feature(CPU_FTR_ARCH_207S))
+               wmask = SRR1_WAKEMASK_P8;
+
        idle_states = pnv_get_supported_cpuidle_states();
        /* We don't want to take decrementer interrupts while we are offline,
         * so clear LPCR:PECE1. We keep PECE2 enabled.
@@ -191,10 +197,14 @@ static void pnv_smp_cpu_kill_self(void)
                 * having finished executing in a KVM guest, then srr1
                 * contains 0.
                 */
-               if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) {
+               if ((srr1 & wmask) == SRR1_WAKEEE) {
                        icp_native_flush_interrupt();
                        local_paca->irq_happened &= PACA_IRQ_HARD_DIS;
                        smp_mb();
+               } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
+                       unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
+                       asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
+                       kvmppc_set_host_ipi(cpu, 0);
                }
 
                if (cpu_core_split_required())
index 1d3d52dc3ff31ed6ce0ab9b554c45c1233d0f039..7803a19adb31822fbe1c679160ff7655ec5c5411 100644 (file)
@@ -1340,3 +1340,5 @@ static int __init disable_multitce(char *str)
 }
 
 __setup("multitce=", disable_multitce);
+
+machine_subsys_initcall_sync(pseries, tce_iommu_bus_notifier_init);
index 90cf3dcbd9f268b5430a1cb69bb44cd0fd75d54a..8f35d525cede8327ac73c2129810d83456d35c15 100644 (file)
 static struct kobject *mobility_kobj;
 
 struct update_props_workarea {
-       u32 phandle;
-       u32 state;
-       u64 reserved;
-       u32 nprops;
+       __be32 phandle;
+       __be32 state;
+       __be64 reserved;
+       __be32 nprops;
 } __packed;
 
 #define NODE_ACTION_MASK       0xff000000
@@ -54,11 +54,11 @@ static int mobility_rtas_call(int token, char *buf, s32 scope)
        return rc;
 }
 
-static int delete_dt_node(u32 phandle)
+static int delete_dt_node(__be32 phandle)
 {
        struct device_node *dn;
 
-       dn = of_find_node_by_phandle(phandle);
+       dn = of_find_node_by_phandle(be32_to_cpu(phandle));
        if (!dn)
                return -ENOENT;
 
@@ -127,7 +127,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
        return 0;
 }
 
-static int update_dt_node(u32 phandle, s32 scope)
+static int update_dt_node(__be32 phandle, s32 scope)
 {
        struct update_props_workarea *upwa;
        struct device_node *dn;
@@ -136,6 +136,7 @@ static int update_dt_node(u32 phandle, s32 scope)
        char *prop_data;
        char *rtas_buf;
        int update_properties_token;
+       u32 nprops;
        u32 vd;
 
        update_properties_token = rtas_token("ibm,update-properties");
@@ -146,7 +147,7 @@ static int update_dt_node(u32 phandle, s32 scope)
        if (!rtas_buf)
                return -ENOMEM;
 
-       dn = of_find_node_by_phandle(phandle);
+       dn = of_find_node_by_phandle(be32_to_cpu(phandle));
        if (!dn) {
                kfree(rtas_buf);
                return -ENOENT;
@@ -162,6 +163,7 @@ static int update_dt_node(u32 phandle, s32 scope)
                        break;
 
                prop_data = rtas_buf + sizeof(*upwa);
+               nprops = be32_to_cpu(upwa->nprops);
 
                /* On the first call to ibm,update-properties for a node the
                 * the first property value descriptor contains an empty
@@ -170,17 +172,17 @@ static int update_dt_node(u32 phandle, s32 scope)
                 */
                if (*prop_data == 0) {
                        prop_data++;
-                       vd = *(u32 *)prop_data;
+                       vd = be32_to_cpu(*(__be32 *)prop_data);
                        prop_data += vd + sizeof(vd);
-                       upwa->nprops--;
+                       nprops--;
                }
 
-               for (i = 0; i < upwa->nprops; i++) {
+               for (i = 0; i < nprops; i++) {
                        char *prop_name;
 
                        prop_name = prop_data;
                        prop_data += strlen(prop_name) + 1;
-                       vd = *(u32 *)prop_data;
+                       vd = be32_to_cpu(*(__be32 *)prop_data);
                        prop_data += sizeof(vd);
 
                        switch (vd) {
@@ -212,13 +214,13 @@ static int update_dt_node(u32 phandle, s32 scope)
        return 0;
 }
 
-static int add_dt_node(u32 parent_phandle, u32 drc_index)
+static int add_dt_node(__be32 parent_phandle, __be32 drc_index)
 {
        struct device_node *dn;
        struct device_node *parent_dn;
        int rc;
 
-       parent_dn = of_find_node_by_phandle(parent_phandle);
+       parent_dn = of_find_node_by_phandle(be32_to_cpu(parent_phandle));
        if (!parent_dn)
                return -ENOENT;
 
@@ -237,7 +239,7 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index)
 int pseries_devicetree_update(s32 scope)
 {
        char *rtas_buf;
-       u32 *data;
+       __be32 *data;
        int update_nodes_token;
        int rc;
 
@@ -254,17 +256,17 @@ int pseries_devicetree_update(s32 scope)
                if (rc && rc != 1)
                        break;
 
-               data = (u32 *)rtas_buf + 4;
-               while (*data & NODE_ACTION_MASK) {
+               data = (__be32 *)rtas_buf + 4;
+               while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
                        int i;
-                       u32 action = *data & NODE_ACTION_MASK;
-                       int node_count = *data & NODE_COUNT_MASK;
+                       u32 action = be32_to_cpu(*data) & NODE_ACTION_MASK;
+                       u32 node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
 
                        data++;
 
                        for (i = 0; i < node_count; i++) {
-                               u32 phandle = *data++;
-                               u32 drc_index;
+                               __be32 phandle = *data++;
+                               __be32 drc_index;
 
                                switch (action) {
                                case DELETE_DT_NODE:
index c9df40b5c0ac1915eac7d6a794b25f7f9d6173b5..c9c875d9ed318cc75f7123a8d999b464201a4fd5 100644 (file)
@@ -211,7 +211,7 @@ do {                                                                \
 
 extern unsigned long mmap_rnd_mask;
 
-#define STACK_RND_MASK (mmap_rnd_mask)
+#define STACK_RND_MASK (test_thread_flag(TIF_31BIT) ? 0x7ff : mmap_rnd_mask)
 
 #define ARCH_DLINFO                                                        \
 do {                                                                       \
index d84559e31f3222c9dc9500c07750beccb733ab82..f407bbf5ee94ca5e2f6122951e52ce2d7db1a7ef 100644 (file)
@@ -515,15 +515,15 @@ struct s390_io_adapter {
 #define S390_ARCH_FAC_MASK_SIZE_U64 \
        (S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))
 
-struct s390_model_fac {
-       /* facilities used in SIE context */
-       __u64 sie[S390_ARCH_FAC_LIST_SIZE_U64];
-       /* subset enabled by kvm */
-       __u64 kvm[S390_ARCH_FAC_LIST_SIZE_U64];
+struct kvm_s390_fac {
+       /* facility list requested by guest */
+       __u64 list[S390_ARCH_FAC_LIST_SIZE_U64];
+       /* facility mask supported by kvm & hosting machine */
+       __u64 mask[S390_ARCH_FAC_LIST_SIZE_U64];
 };
 
 struct kvm_s390_cpu_model {
-       struct s390_model_fac *fac;
+       struct kvm_s390_fac *fac;
        struct cpuid cpu_id;
        unsigned short ibc;
 };
index f49b719546541d7dad60d78fd1a1d86daec1f7c2..8fb3802f8fad0f8ff150ae14250fc73b8936ab78 100644 (file)
@@ -62,6 +62,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        int cpu = smp_processor_id();
 
+       S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd);
        if (prev == next)
                return;
        if (MACHINE_HAS_TLB_LC)
@@ -73,7 +74,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        atomic_dec(&prev->context.attach_count);
        if (MACHINE_HAS_TLB_LC)
                cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
-       S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd);
 }
 
 #define finish_arch_post_lock_switch finish_arch_post_lock_switch
index 7b2ac6e44166ac258ebd6481cb1691e77be53b71..53eacbd4f09bf4c32ac051f1be7f9d3e5445e0df 100644 (file)
@@ -37,16 +37,7 @@ static inline void storage_key_init_range(unsigned long start, unsigned long end
 #endif
 }
 
-static inline void clear_page(void *page)
-{
-       register unsigned long reg1 asm ("1") = 0;
-       register void *reg2 asm ("2") = page;
-       register unsigned long reg3 asm ("3") = 4096;
-       asm volatile(
-               "       mvcl    2,0"
-               : "+d" (reg2), "+d" (reg3) : "d" (reg1)
-               : "memory", "cc");
-}
+#define clear_page(page)       memset((page), 0, PAGE_SIZE)
 
 /*
  * copy_page uses the mvcl instruction with 0xb0 padding byte in order to
index fbb5ee3ae57c6d21b589a2a3f38437a17a218f2b..e08ec38f8c6eb74b7cf998e18e022db4c206b616 100644 (file)
@@ -91,7 +91,9 @@ extern unsigned long zero_page_mask;
  */
 #define PTRS_PER_PTE   256
 #ifndef CONFIG_64BIT
+#define __PAGETABLE_PUD_FOLDED
 #define PTRS_PER_PMD   1
+#define __PAGETABLE_PMD_FOLDED
 #define PTRS_PER_PUD   1
 #else /* CONFIG_64BIT */
 #define PTRS_PER_PMD   2048
index 82c19899574f83070158c09c5eed5b438bc092c1..6c79f1b44fe7f7aafd8b5379833fb6ae42cf6f72 100644 (file)
 
 unsigned long ftrace_plt;
 
+static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn)
+{
+#ifdef CC_USING_HOTPATCH
+       /* brcl 0,0 */
+       insn->opc = 0xc004;
+       insn->disp = 0;
+#else
+       /* stg r14,8(r15) */
+       insn->opc = 0xe3e0;
+       insn->disp = 0xf0080024;
+#endif
+}
+
+static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       if (insn->opc == BREAKPOINT_INSTRUCTION)
+               return 1;
+#endif
+       return 0;
+}
+
+static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       insn->opc = BREAKPOINT_INSTRUCTION;
+       insn->disp = KPROBE_ON_FTRACE_NOP;
+#endif
+}
+
+static inline void ftrace_generate_kprobe_call_insn(struct ftrace_insn *insn)
+{
+#ifdef CONFIG_KPROBES
+       insn->opc = BREAKPOINT_INSTRUCTION;
+       insn->disp = KPROBE_ON_FTRACE_CALL;
+#endif
+}
+
 int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
                       unsigned long addr)
 {
@@ -72,16 +110,9 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                return -EFAULT;
        if (addr == MCOUNT_ADDR) {
                /* Initial code replacement */
-#ifdef CC_USING_HOTPATCH
-               /* We expect to see brcl 0,0 */
-               ftrace_generate_nop_insn(&orig);
-#else
-               /* We expect to see stg r14,8(r15) */
-               orig.opc = 0xe3e0;
-               orig.disp = 0xf0080024;
-#endif
+               ftrace_generate_orig_insn(&orig);
                ftrace_generate_nop_insn(&new);
-       } else if (old.opc == BREAKPOINT_INSTRUCTION) {
+       } else if (is_kprobe_on_ftrace(&old)) {
                /*
                 * If we find a breakpoint instruction, a kprobe has been
                 * placed at the beginning of the function. We write the
@@ -89,9 +120,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                 * bytes of the original instruction so that the kprobes
                 * handler can execute a nop, if it reaches this breakpoint.
                 */
-               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
-               orig.disp = KPROBE_ON_FTRACE_CALL;
-               new.disp = KPROBE_ON_FTRACE_NOP;
+               ftrace_generate_kprobe_call_insn(&orig);
+               ftrace_generate_kprobe_nop_insn(&new);
        } else {
                /* Replace ftrace call with a nop. */
                ftrace_generate_call_insn(&orig, rec->ip);
@@ -111,7 +141,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 
        if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
                return -EFAULT;
-       if (old.opc == BREAKPOINT_INSTRUCTION) {
+       if (is_kprobe_on_ftrace(&old)) {
                /*
                 * If we find a breakpoint instruction, a kprobe has been
                 * placed at the beginning of the function. We write the
@@ -119,9 +149,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
                 * bytes of the original instruction so that the kprobes
                 * handler can execute a brasl if it reaches this breakpoint.
                 */
-               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
-               orig.disp = KPROBE_ON_FTRACE_NOP;
-               new.disp = KPROBE_ON_FTRACE_CALL;
+               ftrace_generate_kprobe_nop_insn(&orig);
+               ftrace_generate_kprobe_call_insn(&new);
        } else {
                /* Replace nop with an ftrace call. */
                ftrace_generate_nop_insn(&orig);
index cb2d51e779dfafe0bf02077bdd68918dde731511..830066f936c8ffbb6c5359f600f3b1d4a6f7c747 100644 (file)
@@ -36,16 +36,20 @@ static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
        insn->offset = (entry->target - entry->code) >> 1;
 }
 
-static void jump_label_bug(struct jump_entry *entry, struct insn *insn)
+static void jump_label_bug(struct jump_entry *entry, struct insn *expected,
+                          struct insn *new)
 {
        unsigned char *ipc = (unsigned char *)entry->code;
-       unsigned char *ipe = (unsigned char *)insn;
+       unsigned char *ipe = (unsigned char *)expected;
+       unsigned char *ipn = (unsigned char *)new;
 
        pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc, ipc);
        pr_emerg("Found:    %02x %02x %02x %02x %02x %02x\n",
                 ipc[0], ipc[1], ipc[2], ipc[3], ipc[4], ipc[5]);
        pr_emerg("Expected: %02x %02x %02x %02x %02x %02x\n",
                 ipe[0], ipe[1], ipe[2], ipe[3], ipe[4], ipe[5]);
+       pr_emerg("New:      %02x %02x %02x %02x %02x %02x\n",
+                ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], ipn[5]);
        panic("Corrupted kernel text");
 }
 
@@ -69,10 +73,10 @@ static void __jump_label_transform(struct jump_entry *entry,
        }
        if (init) {
                if (memcmp((void *)entry->code, &orignop, sizeof(orignop)))
-                       jump_label_bug(entry, &old);
+                       jump_label_bug(entry, &orignop, &new);
        } else {
                if (memcmp((void *)entry->code, &old, sizeof(old)))
-                       jump_label_bug(entry, &old);
+                       jump_label_bug(entry, &old, &new);
        }
        probe_kernel_write((void *)entry->code, &new, sizeof(new));
 }
index 36154a2f1814f71a036b68713eeaaf9b1bea7f1f..2ca95862e336d0a040ccc4d968f7aa20da8c4056 100644 (file)
@@ -436,6 +436,7 @@ int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
+       jump_label_apply_nops(me);
        vfree(me->arch.syminfo);
        me->arch.syminfo = NULL;
        return 0;
index c3f8d157cb0d11898bbd72d103dd7b4aceb4b654..e6a1578fc00095929db02b51d4894fe9ad59802c 100644 (file)
@@ -1415,7 +1415,7 @@ CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC_DIAG, PERF_EVENT_CPUM_SF_DIAG);
 
 static struct attribute *cpumsf_pmu_events_attr[] = {
        CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC),
-       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG),
+       NULL,
        NULL,
 };
 
@@ -1606,8 +1606,11 @@ static int __init init_cpum_sampling_pmu(void)
                return -EINVAL;
        }
 
-       if (si.ad)
+       if (si.ad) {
                sfb_set_limits(CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB);
+               cpumsf_pmu_events_attr[1] =
+                       CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG);
+       }
 
        sfdbg = debug_register(KMSG_COMPONENT, 2, 1, 80);
        if (!sfdbg)
index 26108232fcaaf049f4e4caa3938e537af5066ac6..dc488e13b7e35b216335323a68bd6eac422ce172 100644 (file)
@@ -18,7 +18,7 @@
 
 static DEFINE_PER_CPU(struct cpuid, cpu_id);
 
-void cpu_relax(void)
+void notrace cpu_relax(void)
 {
        if (!smp_cpu_mtid && MACHINE_HAS_DIAG44)
                asm volatile("diag 0,0,0x44");
index 6b09fdffbd2f7e7a787ca5100f074be15ff71f33..ca6294645dd37eeec22c4ab3d26226da37686cd0 100644 (file)
@@ -177,6 +177,17 @@ restart_entry:
        lhi     %r1,1
        sigp    %r1,%r0,SIGP_SET_ARCHITECTURE
        sam64
+#ifdef CONFIG_SMP
+       larl    %r1,smp_cpu_mt_shift
+       icm     %r1,15,0(%r1)
+       jz      smt_done
+       llgfr   %r1,%r1
+smt_loop:
+       sigp    %r1,%r0,SIGP_SET_MULTI_THREADING
+       brc     8,smt_done                      /* accepted */
+       brc     2,smt_loop                      /* busy, try again */
+smt_done:
+#endif
        larl    %r1,.Lnew_pgm_check_psw
        lpswe   0(%r1)
 pgm_check_entry:
index 0c362392756310e1ce0e2da8e35c6bedb5cf0849..19e17bd7aec09b2662874a3925e3d55f4e4207f4 100644 (file)
@@ -165,7 +165,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_ONE_REG:
        case KVM_CAP_ENABLE_CAP:
        case KVM_CAP_S390_CSS_SUPPORT:
-       case KVM_CAP_IRQFD:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_DEVICE_CTRL:
        case KVM_CAP_ENABLE_CAP_VM:
@@ -522,7 +521,7 @@ static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr)
                memcpy(&kvm->arch.model.cpu_id, &proc->cpuid,
                       sizeof(struct cpuid));
                kvm->arch.model.ibc = proc->ibc;
-               memcpy(kvm->arch.model.fac->kvm, proc->fac_list,
+               memcpy(kvm->arch.model.fac->list, proc->fac_list,
                       S390_ARCH_FAC_LIST_SIZE_BYTE);
        } else
                ret = -EFAULT;
@@ -556,7 +555,7 @@ static int kvm_s390_get_processor(struct kvm *kvm, struct kvm_device_attr *attr)
        }
        memcpy(&proc->cpuid, &kvm->arch.model.cpu_id, sizeof(struct cpuid));
        proc->ibc = kvm->arch.model.ibc;
-       memcpy(&proc->fac_list, kvm->arch.model.fac->kvm, S390_ARCH_FAC_LIST_SIZE_BYTE);
+       memcpy(&proc->fac_list, kvm->arch.model.fac->list, S390_ARCH_FAC_LIST_SIZE_BYTE);
        if (copy_to_user((void __user *)attr->addr, proc, sizeof(*proc)))
                ret = -EFAULT;
        kfree(proc);
@@ -576,10 +575,10 @@ static int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr)
        }
        get_cpu_id((struct cpuid *) &mach->cpuid);
        mach->ibc = sclp_get_ibc();
-       memcpy(&mach->fac_mask, kvm_s390_fac_list_mask,
-              kvm_s390_fac_list_mask_size() * sizeof(u64));
+       memcpy(&mach->fac_mask, kvm->arch.model.fac->mask,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        memcpy((unsigned long *)&mach->fac_list, S390_lowcore.stfle_fac_list,
-              S390_ARCH_FAC_LIST_SIZE_U64);
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        if (copy_to_user((void __user *)attr->addr, mach, sizeof(*mach)))
                ret = -EFAULT;
        kfree(mach);
@@ -778,15 +777,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
 static int kvm_s390_query_ap_config(u8 *config)
 {
        u32 fcn_code = 0x04000000UL;
-       u32 cc;
+       u32 cc = 0;
 
+       memset(config, 0, 128);
        asm volatile(
                "lgr 0,%1\n"
                "lgr 2,%2\n"
                ".long 0xb2af0000\n"            /* PQAP(QCI) */
-               "ipm %0\n"
+               "0: ipm %0\n"
                "srl %0,28\n"
-               : "=r" (cc)
+               "1:\n"
+               EX_TABLE(0b, 1b)
+               : "+r" (cc)
                : "r" (fcn_code), "r" (config)
                : "cc", "0", "2", "memory"
        );
@@ -839,9 +841,13 @@ static int kvm_s390_crypto_init(struct kvm *kvm)
 
        kvm_s390_set_crycb_format(kvm);
 
-       /* Disable AES/DEA protected key functions by default */
-       kvm->arch.crypto.aes_kw = 0;
-       kvm->arch.crypto.dea_kw = 0;
+       /* Enable AES/DEA protected key functions by default */
+       kvm->arch.crypto.aes_kw = 1;
+       kvm->arch.crypto.dea_kw = 1;
+       get_random_bytes(kvm->arch.crypto.crycb->aes_wrapping_key_mask,
+                        sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask));
+       get_random_bytes(kvm->arch.crypto.crycb->dea_wrapping_key_mask,
+                        sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask));
 
        return 0;
 }
@@ -886,40 +892,29 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        /*
         * The architectural maximum amount of facilities is 16 kbit. To store
         * this amount, 2 kbyte of memory is required. Thus we need a full
-        * page to hold the active copy (arch.model.fac->sie) and the current
-        * facilities set (arch.model.fac->kvm). Its address size has to be
+        * page to hold the guest facility list (arch.model.fac->list) and the
+        * facility mask (arch.model.fac->mask). Its address size has to be
         * 31 bits and word aligned.
         */
        kvm->arch.model.fac =
-               (struct s390_model_fac *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+               (struct kvm_s390_fac *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!kvm->arch.model.fac)
                goto out_nofac;
 
-       memcpy(kvm->arch.model.fac->kvm, S390_lowcore.stfle_fac_list,
-              S390_ARCH_FAC_LIST_SIZE_U64);
-
-       /*
-        * If this KVM host runs *not* in a LPAR, relax the facility bits
-        * of the kvm facility mask by all missing facilities. This will allow
-        * to determine the right CPU model by means of the remaining facilities.
-        * Live guest migration must prohibit the migration of KVMs running in
-        * a LPAR to non LPAR hosts.
-        */
-       if (!MACHINE_IS_LPAR)
-               for (i = 0; i < kvm_s390_fac_list_mask_size(); i++)
-                       kvm_s390_fac_list_mask[i] &= kvm->arch.model.fac->kvm[i];
-
-       /*
-        * Apply the kvm facility mask to limit the kvm supported/tolerated
-        * facility list.
-        */
+       /* Populate the facility mask initially. */
+       memcpy(kvm->arch.model.fac->mask, S390_lowcore.stfle_fac_list,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
        for (i = 0; i < S390_ARCH_FAC_LIST_SIZE_U64; i++) {
                if (i < kvm_s390_fac_list_mask_size())
-                       kvm->arch.model.fac->kvm[i] &= kvm_s390_fac_list_mask[i];
+                       kvm->arch.model.fac->mask[i] &= kvm_s390_fac_list_mask[i];
                else
-                       kvm->arch.model.fac->kvm[i] = 0UL;
+                       kvm->arch.model.fac->mask[i] = 0UL;
        }
 
+       /* Populate the facility list initially. */
+       memcpy(kvm->arch.model.fac->list, kvm->arch.model.fac->mask,
+              S390_ARCH_FAC_LIST_SIZE_BYTE);
+
        kvm_s390_get_cpu_id(&kvm->arch.model.cpu_id);
        kvm->arch.model.ibc = sclp_get_ibc() & 0x0fff;
 
@@ -1165,8 +1160,6 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 
        mutex_lock(&vcpu->kvm->lock);
        vcpu->arch.cpu_id = vcpu->kvm->arch.model.cpu_id;
-       memcpy(vcpu->kvm->arch.model.fac->sie, vcpu->kvm->arch.model.fac->kvm,
-              S390_ARCH_FAC_LIST_SIZE_BYTE);
        vcpu->arch.sie_block->ibc = vcpu->kvm->arch.model.ibc;
        mutex_unlock(&vcpu->kvm->lock);
 
@@ -1212,7 +1205,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
                set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
        }
-       vcpu->arch.sie_block->fac = (int) (long) kvm->arch.model.fac->sie;
+       vcpu->arch.sie_block->fac = (int) (long) kvm->arch.model.fac->list;
 
        spin_lock_init(&vcpu->arch.local_int.lock);
        vcpu->arch.local_int.float_int = &kvm->arch.float_int;
index 985c2114d7ef3b9d2b50eb9c33acd314ae9fa3ae..c34109aa552d9b1a6e5ea66f172b5c3e30ad001b 100644 (file)
@@ -128,7 +128,8 @@ static inline void kvm_s390_set_psw_cc(struct kvm_vcpu *vcpu, unsigned long cc)
 /* test availability of facility in a kvm intance */
 static inline int test_kvm_facility(struct kvm *kvm, unsigned long nr)
 {
-       return __test_facility(nr, kvm->arch.model.fac->kvm);
+       return __test_facility(nr, kvm->arch.model.fac->mask) &&
+               __test_facility(nr, kvm->arch.model.fac->list);
 }
 
 /* are cpu states controlled by user space */
index bdd9b5b17e03ed3ab113e73c955f35fbeb8d1560..351116939ea27f2fcf6eb4de60447d86335d0b6e 100644 (file)
@@ -348,7 +348,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
         * We need to shift the lower 32 facility bits (bit 0-31) from a u64
         * into a u32 memory representation. They will remain bits 0-31.
         */
-       fac = *vcpu->kvm->arch.model.fac->sie >> 32;
+       fac = *vcpu->kvm->arch.model.fac->list >> 32;
        rc = write_guest_lc(vcpu, offsetof(struct _lowcore, stfl_fac_list),
                            &fac, sizeof(fac));
        if (rc)
index 753a5673195112051667031bfee73921e149eef1..f0b85443e06093d2f5d3d4c5dbe85554e459c138 100644 (file)
@@ -287,7 +287,7 @@ void __iomem *pci_iomap_range(struct pci_dev *pdev,
        addr = ZPCI_IOMAP_ADDR_BASE | ((u64) idx << 48);
        return (void __iomem *) addr + offset;
 }
-EXPORT_SYMBOL_GPL(pci_iomap_range);
+EXPORT_SYMBOL(pci_iomap_range);
 
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
 {
@@ -309,7 +309,7 @@ void pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
        }
        spin_unlock(&zpci_iomap_lock);
 }
-EXPORT_SYMBOL_GPL(pci_iounmap);
+EXPORT_SYMBOL(pci_iounmap);
 
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
                    int size, u32 *val)
@@ -483,9 +483,8 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev)
        airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
 }
 
-static void zpci_map_resources(struct zpci_dev *zdev)
+static void zpci_map_resources(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = zdev->pdev;
        resource_size_t len;
        int i;
 
@@ -499,9 +498,8 @@ static void zpci_map_resources(struct zpci_dev *zdev)
        }
 }
 
-static void zpci_unmap_resources(struct zpci_dev *zdev)
+static void zpci_unmap_resources(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = zdev->pdev;
        resource_size_t len;
        int i;
 
@@ -651,7 +649,7 @@ int pcibios_add_device(struct pci_dev *pdev)
 
        zdev->pdev = pdev;
        pdev->dev.groups = zpci_attr_groups;
-       zpci_map_resources(zdev);
+       zpci_map_resources(pdev);
 
        for (i = 0; i < PCI_BAR_COUNT; i++) {
                res = &pdev->resource[i];
@@ -663,6 +661,11 @@ int pcibios_add_device(struct pci_dev *pdev)
        return 0;
 }
 
+void pcibios_release_device(struct pci_dev *pdev)
+{
+       zpci_unmap_resources(pdev);
+}
+
 int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
@@ -670,7 +673,6 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
        zdev->pdev = pdev;
        zpci_debug_init_device(zdev);
        zpci_fmb_enable_device(zdev);
-       zpci_map_resources(zdev);
 
        return pci_enable_resources(pdev, mask);
 }
@@ -679,7 +681,6 @@ void pcibios_disable_device(struct pci_dev *pdev)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
 
-       zpci_unmap_resources(zdev);
        zpci_fmb_disable_device(zdev);
        zpci_debug_exit_device(zdev);
        zdev->pdev = NULL;
@@ -688,7 +689,8 @@ void pcibios_disable_device(struct pci_dev *pdev)
 #ifdef CONFIG_HIBERNATE_CALLBACKS
 static int zpci_restore(struct device *dev)
 {
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct zpci_dev *zdev = get_zdev(pdev);
        int ret = 0;
 
        if (zdev->state != ZPCI_FN_STATE_ONLINE)
@@ -698,7 +700,7 @@ static int zpci_restore(struct device *dev)
        if (ret)
                goto out;
 
-       zpci_map_resources(zdev);
+       zpci_map_resources(pdev);
        zpci_register_ioat(zdev, 0, zdev->start_dma + PAGE_OFFSET,
                           zdev->start_dma + zdev->iommu_size - 1,
                           (u64) zdev->dma_table);
@@ -709,12 +711,14 @@ out:
 
 static int zpci_freeze(struct device *dev)
 {
-       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct zpci_dev *zdev = get_zdev(pdev);
 
        if (zdev->state != ZPCI_FN_STATE_ONLINE)
                return 0;
 
        zpci_unregister_ioat(zdev, 0);
+       zpci_unmap_resources(pdev);
        return clp_disable_fh(zdev);
 }
 
index 8aa271b3d1ad95b79cb0fa40d130ab76d26fc2bd..b1bb2b72302ca43836720f5232af0a43b0db8d12 100644 (file)
@@ -64,8 +64,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
        if (copy_from_user(buf, user_buffer, length))
                goto out;
 
-       memcpy_toio(io_addr, buf, length);
-       ret = 0;
+       ret = zpci_memcpy_toio(io_addr, buf, length);
 out:
        if (buf != local_buf)
                kfree(buf);
@@ -98,16 +97,16 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
                goto out;
        io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
 
-       ret = -EFAULT;
-       if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
+       if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) {
+               ret = -EFAULT;
                goto out;
-
-       memcpy_fromio(buf, io_addr, length);
-
-       if (copy_to_user(user_buffer, buf, length))
+       }
+       ret = zpci_memcpy_fromio(buf, io_addr, length);
+       if (ret)
                goto out;
+       if (copy_to_user(user_buffer, buf, length))
+               ret = -EFAULT;
 
-       ret = 0;
 out:
        if (buf != local_buf)
                kfree(buf);
index 96ac69c5eba016a7b5c1ef93fd35baccf8e2f52b..efb00ec758058afebb97f912e2bc6f142bbd43ff 100644 (file)
@@ -86,6 +86,9 @@ config ARCH_DEFCONFIG
        default "arch/sparc/configs/sparc32_defconfig" if SPARC32
        default "arch/sparc/configs/sparc64_defconfig" if SPARC64
 
+config ARCH_PROC_KCORE_TEXT
+       def_bool y
+
 config IOMMU_HELPER
        bool
        default y if SPARC64
index 4f6725ff4c336878fd3600f840f81897fdc65099..f5b6537306f0b3259e2313f3ec03b3ed32215c49 100644 (file)
@@ -2957,6 +2957,17 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
                                   unsigned long reg_val);
 #endif
 
+
+#define HV_FAST_M7_GET_PERFREG 0x43
+#define HV_FAST_M7_SET_PERFREG 0x44
+
+#ifndef        __ASSEMBLY__
+unsigned long sun4v_m7_get_perfreg(unsigned long reg_num,
+                                     unsigned long *reg_val);
+unsigned long sun4v_m7_set_perfreg(unsigned long reg_num,
+                                     unsigned long reg_val);
+#endif
+
 /* Function numbers for HV_CORE_TRAP.  */
 #define HV_CORE_SET_VER                        0x00
 #define HV_CORE_PUTCHAR                        0x01
@@ -2981,6 +2992,7 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
 #define HV_GRP_SDIO                    0x0108
 #define HV_GRP_SDIO_ERR                        0x0109
 #define HV_GRP_REBOOT_DATA             0x0110
+#define HV_GRP_M7_PERF                 0x0114
 #define HV_GRP_NIAG_PERF               0x0200
 #define HV_GRP_FIRE_PERF               0x0201
 #define HV_GRP_N2_CPU                  0x0202
index 9b672be70dda6e84802853b0cd6acf7d5aa13e08..50d4840d9aebbfa036c7a110e9f866fa77007647 100644 (file)
@@ -407,16 +407,16 @@ static inline void iounmap(volatile void __iomem *addr)
 {
 }
 
-#define ioread8(X)                     readb(X)
-#define ioread16(X)                    readw(X)
-#define ioread16be(X)                  __raw_readw(X)
-#define ioread32(X)                    readl(X)
-#define ioread32be(X)                  __raw_readl(X)
-#define iowrite8(val,X)                        writeb(val,X)
-#define iowrite16(val,X)               writew(val,X)
-#define iowrite16be(val,X)             __raw_writew(val,X)
-#define iowrite32(val,X)               writel(val,X)
-#define iowrite32be(val,X)             __raw_writel(val,X)
+#define ioread8                        readb
+#define ioread16               readw
+#define ioread16be             __raw_readw
+#define ioread32               readl
+#define ioread32be             __raw_readl
+#define iowrite8               writeb
+#define iowrite16              writew
+#define iowrite16be            __raw_writew
+#define iowrite32              writel
+#define iowrite32be            __raw_writel
 
 /* Create a virtual mapping cookie for an IO port range */
 void __iomem *ioport_map(unsigned long port, unsigned int nr);
index c100dc27a0a9461e677e805224c586eb37082793..176fa0ad19f15d2d41a7234378cc36db144abd57 100644 (file)
@@ -12,7 +12,6 @@
 extern int this_is_starfire;
 
 void check_if_starfire(void);
-int starfire_hard_smp_processor_id(void);
 void starfire_hookup(int);
 unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
 
index 88d322b67fac4d4be308280dd59bd52f2ecf92c0..07cc49e541f40ea2cacc1f952aa7e07dd4a4e69b 100644 (file)
@@ -98,11 +98,7 @@ void sun4v_do_mna(struct pt_regs *regs,
 void do_privop(struct pt_regs *regs);
 void do_privact(struct pt_regs *regs);
 void do_cee(struct pt_regs *regs);
-void do_cee_tl1(struct pt_regs *regs);
-void do_dae_tl1(struct pt_regs *regs);
-void do_iae_tl1(struct pt_regs *regs);
 void do_div0_tl1(struct pt_regs *regs);
-void do_fpdis_tl1(struct pt_regs *regs);
 void do_fpieee_tl1(struct pt_regs *regs);
 void do_fpother_tl1(struct pt_regs *regs);
 void do_ill_tl1(struct pt_regs *regs);
index 5c55145bfbf02d616ec606feb94539e26cbe1831..662500fa555f74160f6449143e6d0785af2643e9 100644 (file)
@@ -48,6 +48,7 @@ static struct api_info api_table[] = {
        { .group = HV_GRP_VT_CPU,                               },
        { .group = HV_GRP_T5_CPU,                               },
        { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
+       { .group = HV_GRP_M7_PERF,                              },
 };
 
 static DEFINE_SPINLOCK(hvapi_lock);
index caedf8320416e1fe8bfc4cb76369ce1efd8ce729..afbaba52d2f16cb30daf092f5cd3986e7ca9c299 100644 (file)
@@ -837,3 +837,19 @@ ENTRY(sun4v_t5_set_perfreg)
        retl
         nop
 ENDPROC(sun4v_t5_set_perfreg)
+
+ENTRY(sun4v_m7_get_perfreg)
+       mov     %o1, %o4
+       mov     HV_FAST_M7_GET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       stx     %o1, [%o4]
+       retl
+       nop
+ENDPROC(sun4v_m7_get_perfreg)
+
+ENTRY(sun4v_m7_set_perfreg)
+       mov     HV_FAST_M7_SET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       retl
+       nop
+ENDPROC(sun4v_m7_set_perfreg)
index 7e967c8018c8cf19ba1886b39b087d9eb0638b0c..eb978c77c76a78d401e5dce22b4f5bafa8ef948d 100644 (file)
@@ -217,6 +217,31 @@ static const struct pcr_ops n5_pcr_ops = {
        .pcr_nmi_disable        = PCR_N4_PICNPT,
 };
 
+static u64 m7_pcr_read(unsigned long reg_num)
+{
+       unsigned long val;
+
+       (void) sun4v_m7_get_perfreg(reg_num, &val);
+
+       return val;
+}
+
+static void m7_pcr_write(unsigned long reg_num, u64 val)
+{
+       (void) sun4v_m7_set_perfreg(reg_num, val);
+}
+
+static const struct pcr_ops m7_pcr_ops = {
+       .read_pcr               = m7_pcr_read,
+       .write_pcr              = m7_pcr_write,
+       .read_pic               = n4_pic_read,
+       .write_pic              = n4_pic_write,
+       .nmi_picl_value         = n4_picl_value,
+       .pcr_nmi_enable         = (PCR_N4_PICNPT | PCR_N4_STRACE |
+                                  PCR_N4_UTRACE | PCR_N4_TOE |
+                                  (26 << PCR_N4_SL_SHIFT)),
+       .pcr_nmi_disable        = PCR_N4_PICNPT,
+};
 
 static unsigned long perf_hsvc_group;
 static unsigned long perf_hsvc_major;
@@ -248,6 +273,10 @@ static int __init register_perf_hsvc(void)
                        perf_hsvc_group = HV_GRP_T5_CPU;
                        break;
 
+               case SUN4V_CHIP_SPARC_M7:
+                       perf_hsvc_group = HV_GRP_M7_PERF;
+                       break;
+
                default:
                        return -ENODEV;
                }
@@ -293,6 +322,10 @@ static int __init setup_sun4v_pcr_ops(void)
                pcr_ops = &n5_pcr_ops;
                break;
 
+       case SUN4V_CHIP_SPARC_M7:
+               pcr_ops = &m7_pcr_ops;
+               break;
+
        default:
                ret = -ENODEV;
                break;
index 46a5e4508752814cb0ec21b820673cd445b19ada..86eebfa3b15873dfd60117389e9c80f0018a13e0 100644 (file)
@@ -792,6 +792,42 @@ static const struct sparc_pmu niagara4_pmu = {
        .num_pic_regs   = 4,
 };
 
+static void sparc_m7_write_pmc(int idx, u64 val)
+{
+       u64 pcr;
+
+       pcr = pcr_ops->read_pcr(idx);
+       /* ensure ov and ntc are reset */
+       pcr &= ~(PCR_N4_OV | PCR_N4_NTC);
+
+       pcr_ops->write_pic(idx, val & 0xffffffff);
+
+       pcr_ops->write_pcr(idx, pcr);
+}
+
+static const struct sparc_pmu sparc_m7_pmu = {
+       .event_map      = niagara4_event_map,
+       .cache_map      = &niagara4_cache_map,
+       .max_events     = ARRAY_SIZE(niagara4_perfmon_event_map),
+       .read_pmc       = sparc_vt_read_pmc,
+       .write_pmc      = sparc_m7_write_pmc,
+       .upper_shift    = 5,
+       .lower_shift    = 5,
+       .event_mask     = 0x7ff,
+       .user_bit       = PCR_N4_UTRACE,
+       .priv_bit       = PCR_N4_STRACE,
+
+       /* We explicitly don't support hypervisor tracing. */
+       .hv_bit         = 0,
+
+       .irq_bit        = PCR_N4_TOE,
+       .upper_nop      = 0,
+       .lower_nop      = 0,
+       .flags          = 0,
+       .max_hw_events  = 4,
+       .num_pcrs       = 4,
+       .num_pic_regs   = 4,
+};
 static const struct sparc_pmu *sparc_pmu __read_mostly;
 
 static u64 event_encoding(u64 event_id, int idx)
@@ -960,6 +996,8 @@ out:
        cpuc->pcr[0] |= cpuc->event[0]->hw.config_base;
 }
 
+static void sparc_pmu_start(struct perf_event *event, int flags);
+
 /* On this PMU each PIC has it's own PCR control register.  */
 static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
 {
@@ -972,20 +1010,13 @@ static void calculate_multiple_pcrs(struct cpu_hw_events *cpuc)
                struct perf_event *cp = cpuc->event[i];
                struct hw_perf_event *hwc = &cp->hw;
                int idx = hwc->idx;
-               u64 enc;
 
                if (cpuc->current_idx[i] != PIC_NO_INDEX)
                        continue;
 
-               sparc_perf_event_set_period(cp, hwc, idx);
                cpuc->current_idx[i] = idx;
 
-               enc = perf_event_get_enc(cpuc->events[i]);
-               cpuc->pcr[idx] &= ~mask_for_index(idx);
-               if (hwc->state & PERF_HES_STOPPED)
-                       cpuc->pcr[idx] |= nop_for_index(idx);
-               else
-                       cpuc->pcr[idx] |= event_encoding(enc, idx);
+               sparc_pmu_start(cp, PERF_EF_RELOAD);
        }
 out:
        for (i = 0; i < cpuc->n_events; i++) {
@@ -1101,7 +1132,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags)
        int i;
 
        local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
 
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event[i]) {
@@ -1127,7 +1157,6 @@ static void sparc_pmu_del(struct perf_event *event, int _flags)
                }
        }
 
-       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
 }
 
@@ -1361,7 +1390,6 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags)
        unsigned long flags;
 
        local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
 
        n0 = cpuc->n_events;
        if (n0 >= sparc_pmu->max_hw_events)
@@ -1394,7 +1422,6 @@ nocheck:
 
        ret = 0;
 out:
-       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
        return ret;
 }
@@ -1667,6 +1694,10 @@ static bool __init supported_pmu(void)
                sparc_pmu = &niagara4_pmu;
                return true;
        }
+       if (!strcmp(sparc_pmu_type, "sparc-m7")) {
+               sparc_pmu = &sparc_m7_pmu;
+               return true;
+       }
        return false;
 }
 
index 0be7bf978cb1da03b8d657958ec6d0ec3c4e7d8b..46a59643bb1cee71edbd3d91d3f8f2eb09b3a26a 100644 (file)
@@ -287,6 +287,8 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
                        printk("             TPC[%lx] O7[%lx] I7[%lx] RPC[%lx]\n",
                               gp->tpc, gp->o7, gp->i7, gp->rpc);
                }
+
+               touch_nmi_watchdog();
        }
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
@@ -362,6 +364,8 @@ static void pmu_snapshot_all_cpus(void)
                       (cpu == this_cpu ? '*' : ' '), cpu,
                       pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3],
                       pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]);
+
+               touch_nmi_watchdog();
        }
 
        memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
index da6f1a7fc4db4713425d1927af185cb797b4c1fc..61139d9924cae4a8fdf5d4d5366a31052ea29616 100644 (file)
@@ -1406,11 +1406,32 @@ void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
        scheduler_ipi();
 }
 
-/* This is a nop because we capture all other cpus
- * anyways when making the PROM active.
- */
+static void stop_this_cpu(void *dummy)
+{
+       prom_stopself();
+}
+
 void smp_send_stop(void)
 {
+       int cpu;
+
+       if (tlb_type == hypervisor) {
+               for_each_online_cpu(cpu) {
+                       if (cpu == smp_processor_id())
+                               continue;
+#ifdef CONFIG_SUN_LDOMS
+                       if (ldom_domaining_enabled) {
+                               unsigned long hv_err;
+                               hv_err = sun4v_cpu_stop(cpu);
+                               if (hv_err)
+                                       printk(KERN_ERR "sun4v_cpu_stop() "
+                                              "failed err=%lu\n", hv_err);
+                       } else
+#endif
+                               prom_stopcpu_cpuid(cpu);
+               }
+       } else
+               smp_call_function(stop_this_cpu, NULL, 0);
 }
 
 /**
index 82281a566bb86b866525a18b8fc4ca453d2e1e60..167fdfd9c83702bd2ccdc737625fcc8f57c9619c 100644 (file)
@@ -28,11 +28,6 @@ void check_if_starfire(void)
                this_is_starfire = 1;
 }
 
-int starfire_hard_smp_processor_id(void)
-{
-       return upa_readl(0x1fff40000d0UL);
-}
-
 /*
  * Each Starfire board has 32 registers which perform translation
  * and delivery of traditional interrupt packets into the extended
index c85403d0496c24f7639a32fa06b7dc53c1559381..30e7ddb27a3a966e74e5ab79ad686bab26eab459 100644 (file)
@@ -333,7 +333,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
        long err;
 
        /* No need for backward compatibility. We can start fresh... */
-       if (call <= SEMCTL) {
+       if (call <= SEMTIMEDOP) {
                switch (call) {
                case SEMOP:
                        err = sys_semtimedop(first, ptr,
index a27651e866e7a108dca92cf88c14ec8f21ae5b5b..0e699745d64311d44439327d3e971ce78114b7da 100644 (file)
@@ -2427,6 +2427,8 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs)
                }
                user_instruction_dump ((unsigned int __user *) regs->tpc);
        }
+       if (panic_on_oops)
+               panic("Fatal exception");
        if (regs->tstate & TSTATE_PRIV)
                do_exit(SIGKILL);
        do_exit(SIGSEGV);
@@ -2564,27 +2566,6 @@ void do_cee(struct pt_regs *regs)
        die_if_kernel("TL0: Cache Error Exception", regs);
 }
 
-void do_cee_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Cache Error Exception", regs);
-}
-
-void do_dae_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Data Access Exception", regs);
-}
-
-void do_iae_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: Instruction Access Exception", regs);
-}
-
 void do_div0_tl1(struct pt_regs *regs)
 {
        exception_enter();
@@ -2592,13 +2573,6 @@ void do_div0_tl1(struct pt_regs *regs)
        die_if_kernel("TL1: DIV0 Exception", regs);
 }
 
-void do_fpdis_tl1(struct pt_regs *regs)
-{
-       exception_enter();
-       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
-       die_if_kernel("TL1: FPU Disabled", regs);
-}
-
 void do_fpieee_tl1(struct pt_regs *regs)
 {
        exception_enter();
index b7f6334e159f9d22fc34ccc2f003511009ca9b61..857ad4f8905f942f44ac40770c9277323e4e3c09 100644 (file)
@@ -8,9 +8,11 @@
 
        .text
 ENTRY(memmove) /* o0=dst o1=src o2=len */
-       mov             %o0, %g1
+       brz,pn          %o2, 99f
+        mov            %o0, %g1
+
        cmp             %o0, %o1
-       bleu,pt         %xcc, memcpy
+       bleu,pt         %xcc, 2f
         add            %o1, %o2, %g7
        cmp             %g7, %o0
        bleu,pt         %xcc, memcpy
@@ -24,7 +26,34 @@ ENTRY(memmove) /* o0=dst o1=src o2=len */
        stb             %g7, [%o0]
        bne,pt          %icc, 1b
         sub            %o0, 1, %o0
-
+99:
        retl
         mov            %g1, %o0
+
+       /* We can't just call memcpy for these memmove cases.  On some
+        * chips the memcpy uses cache initializing stores and when dst
+        * and src are close enough, those can clobber the source data
+        * before we've loaded it in.
+        */
+2:     or              %o0, %o1, %g7
+       or              %o2, %g7, %g7
+       andcc           %g7, 0x7, %g0
+       bne,pn          %xcc, 4f
+        nop
+
+3:     ldx             [%o1], %g7
+       add             %o1, 8, %o1
+       subcc           %o2, 8, %o2
+       add             %o0, 8, %o0
+       bne,pt          %icc, 3b
+        stx            %g7, [%o0 - 0x8]
+       ba,a,pt         %xcc, 99b
+
+4:     ldub            [%o1], %g7
+       add             %o1, 1, %o1
+       subcc           %o2, 1, %o2
+       add             %o0, 1, %o0
+       bne,pt          %icc, 4b
+        stb            %g7, [%o0 - 0x1]
+       ba,a,pt         %xcc, 99b
 ENDPROC(memmove)
index 3ea267c53320d49683ab39c9e0d95189e4adb56e..4ca0d6ba5ec8331c67f43f8515eb3737526208bb 100644 (file)
@@ -2820,7 +2820,7 @@ static int __init report_memory(void)
 
        return 0;
 }
-device_initcall(report_memory);
+arch_initcall(report_memory);
 
 #ifdef CONFIG_SMP
 #define do_flush_tlb_kernel_range      smp_flush_tlb_kernel_range
index c2fb8a87dccb2990a794bb8960bfdad85eb9a390..b7d31ca5518744983c77bc8339f30756621dfea0 100644 (file)
@@ -499,6 +499,7 @@ config X86_INTEL_QUARK
        depends on X86_IO_APIC
        select IOSF_MBI
        select INTEL_IMR
+       select COMMON_CLK
        ---help---
          Select to include support for Quark X1000 SoC.
          Say Y here if you have a Quark based system such as the Arduino
index 7083c16cccba0b2b144ea5e03e160ebafe81e855..bb1376381985edb9f96e49c0a1b0269e56bd0f9e 100644 (file)
 static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
                LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
 
-struct kaslr_setup_data {
-       __u64 next;
-       __u32 type;
-       __u32 len;
-       __u8 data[1];
-} kaslr_setup_data;
-
 #define I8254_PORT_CONTROL     0x43
 #define I8254_PORT_COUNTER0    0x40
 #define I8254_CMD_READBACK     0xC0
@@ -302,29 +295,7 @@ static unsigned long find_random_addr(unsigned long minimum,
        return slots_fetch_random();
 }
 
-static void add_kaslr_setup_data(struct boot_params *params, __u8 enabled)
-{
-       struct setup_data *data;
-
-       kaslr_setup_data.type = SETUP_KASLR;
-       kaslr_setup_data.len = 1;
-       kaslr_setup_data.next = 0;
-       kaslr_setup_data.data[0] = enabled;
-
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
-
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
-
-       if (data)
-               data->next = (unsigned long)&kaslr_setup_data;
-       else
-               params->hdr.setup_data = (unsigned long)&kaslr_setup_data;
-
-}
-
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size)
@@ -335,17 +306,14 @@ unsigned char *choose_kernel_location(struct boot_params *params,
 #ifdef CONFIG_HIBERNATION
        if (!cmdline_find_option_bool("kaslr")) {
                debug_putstr("KASLR disabled by default...\n");
-               add_kaslr_setup_data(params, 0);
                goto out;
        }
 #else
        if (cmdline_find_option_bool("nokaslr")) {
                debug_putstr("KASLR disabled by cmdline...\n");
-               add_kaslr_setup_data(params, 0);
                goto out;
        }
 #endif
-       add_kaslr_setup_data(params, 1);
 
        /* Record the various known unsafe memory ranges. */
        mem_avoid_init((unsigned long)input, input_size,
index 5903089c818f6843b9d1cc7c83507cf0d28a3e26..a950864a64dab3d558197c77bef3c56a07961494 100644 (file)
@@ -401,8 +401,7 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
         * the entire decompressed kernel plus relocation table, or the
         * entire decompressed kernel plus .bss and .brk sections.
         */
-       output = choose_kernel_location(real_mode, input_data, input_len,
-                                       output,
+       output = choose_kernel_location(input_data, input_len, output,
                                        output_len > run_size ? output_len
                                                              : run_size);
 
index ee3576b2666b8139eedf25077ce769da10712c11..04477d68403f1fe6197d82276033ce27338c1bac 100644 (file)
@@ -57,8 +57,7 @@ int cmdline_find_option_bool(const char *option);
 
 #if CONFIG_RANDOMIZE_BASE
 /* aslr.c */
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size);
@@ -66,8 +65,7 @@ unsigned char *choose_kernel_location(struct boot_params *params,
 bool has_cpuflag(int flag);
 #else
 static inline
-unsigned char *choose_kernel_location(struct boot_params *params,
-                                     unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
                                      unsigned long input_size,
                                      unsigned char *output,
                                      unsigned long output_size)
index 947c6bf52c330452cfb7ac4a19d368f68f4e4509..54f60ab41c63025fd2cb42e5579df7f69c3d9b60 100644 (file)
@@ -1155,7 +1155,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
                src = kmalloc(req->cryptlen + req->assoclen, GFP_ATOMIC);
                if (!src)
                        return -ENOMEM;
-               assoc = (src + req->cryptlen + auth_tag_len);
+               assoc = (src + req->cryptlen);
                scatterwalk_map_and_copy(src, req->src, 0, req->cryptlen, 0);
                scatterwalk_map_and_copy(assoc, req->assoc, 0,
                        req->assoclen, 0);
@@ -1180,7 +1180,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
                scatterwalk_done(&src_sg_walk, 0, 0);
                scatterwalk_done(&assoc_sg_walk, 0, 0);
        } else {
-               scatterwalk_map_and_copy(dst, req->dst, 0, req->cryptlen, 1);
+               scatterwalk_map_and_copy(dst, req->dst, 0, tempCipherLen, 1);
                kfree(src);
        }
        return retval;
index 0dbc08282291044216456e6c14a802d56a0e40d8..72ba21a8b5fc2ff8b76c6c3e53b331ca6a558339 100644 (file)
@@ -370,7 +370,7 @@ static inline void drop_fpu(struct task_struct *tsk)
        preempt_disable();
        tsk->thread.fpu_counter = 0;
        __drop_fpu(tsk);
-       clear_used_math();
+       clear_stopped_child_used_math(tsk);
        preempt_enable();
 }
 
index 95e11f79f123c6aadd5ed8888a51e1870405deeb..f97fbe3abb67f5059d4e6f0a37261d6113df19de 100644 (file)
@@ -51,8 +51,6 @@ extern int devmem_is_allowed(unsigned long pagenr);
 extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
 
-extern bool kaslr_enabled;
-
 static inline phys_addr_t get_max_mapped(void)
 {
        return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
index fa1195dae42541aaa1d836782a3a65aa25640e74..164e3f8d3c3dbb6eb4fc0ea60e01cae15fe5116e 100644 (file)
@@ -93,6 +93,8 @@ extern raw_spinlock_t pci_config_lock;
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
 extern void (*pcibios_disable_irq)(struct pci_dev *dev);
 
+extern bool mp_should_keep_irq(struct device *dev);
+
 struct pci_raw_ops {
        int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
                                                int reg, int len, u32 *val);
index 5fa9770035dc935c0a90899f470e668ab889ec7f..c9a6d68b8d623b84d169f61c4680c194ea8d137a 100644 (file)
@@ -82,18 +82,15 @@ static inline int xsave_state_booting(struct xsave_struct *fx, u64 mask)
        if (boot_cpu_has(X86_FEATURE_XSAVES))
                asm volatile("1:"XSAVES"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
        else
                asm volatile("1:"XSAVE"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
-
-       asm volatile(xstate_fault
-                    : "0" (0)
-                    : "memory");
-
        return err;
 }
 
@@ -112,18 +109,15 @@ static inline int xrstor_state_booting(struct xsave_struct *fx, u64 mask)
        if (boot_cpu_has(X86_FEATURE_XSAVES))
                asm volatile("1:"XRSTORS"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
        else
                asm volatile("1:"XRSTOR"\n\t"
                        "2:\n\t"
-                       : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+                            xstate_fault
+                       : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                        :   "memory");
-
-       asm volatile(xstate_fault
-                    : "0" (0)
-                    : "memory");
-
        return err;
 }
 
@@ -149,9 +143,9 @@ static inline int xsave_state(struct xsave_struct *fx, u64 mask)
         */
        alternative_input_2(
                "1:"XSAVE,
-               "1:"XSAVEOPT,
+               XSAVEOPT,
                X86_FEATURE_XSAVEOPT,
-               "1:"XSAVES,
+               XSAVES,
                X86_FEATURE_XSAVES,
                [fx] "D" (fx), "a" (lmask), "d" (hmask) :
                "memory");
@@ -178,7 +172,7 @@ static inline int xrstor_state(struct xsave_struct *fx, u64 mask)
         */
        alternative_input(
                "1: " XRSTOR,
-               "1: " XRSTORS,
+               XRSTORS,
                X86_FEATURE_XSAVES,
                "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
                : "memory");
index 44e6dd7e36a23becd48def85b218b1d70ac938e6..225b0988043a0a78ac9092a9af7a265122c685cd 100644 (file)
@@ -7,7 +7,6 @@
 #define SETUP_DTB                      2
 #define SETUP_PCI                      3
 #define SETUP_EFI                      4
-#define SETUP_KASLR                    5
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
index 3d525c6124f6c720e02d2761b283151be97cf6d7..803b684676ff3d0bcc6a17c530a457efcf485fca 100644 (file)
@@ -1337,6 +1337,26 @@ static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
        return 0;
 }
 
+/*
+ * ACPI offers an alternative platform interface model that removes
+ * ACPI hardware requirements for platforms that do not implement
+ * the PC Architecture.
+ *
+ * We initialize the Hardware-reduced ACPI model here:
+ */
+static void __init acpi_reduced_hw_init(void)
+{
+       if (acpi_gbl_reduced_hardware) {
+               /*
+                * Override x86_init functions and bypass legacy pic
+                * in Hardware-reduced ACPI mode
+                */
+               x86_init.timers.timer_init      = x86_init_noop;
+               x86_init.irqs.pre_vector_init   = x86_init_noop;
+               legacy_pic                      = &null_legacy_pic;
+       }
+}
+
 /*
  * If your system is blacklisted here, but you find that acpi=force
  * works for you, please contact linux-acpi@vger.kernel.org
@@ -1536,6 +1556,11 @@ int __init early_acpi_boot_init(void)
         */
        early_acpi_process_madt();
 
+       /*
+        * Hardware-reduced ACPI mode initialization:
+        */
+       acpi_reduced_hw_init();
+
        return 0;
 }
 
index c2fd21fed00284066ab138354a4daefbc1b775ac..017149cded0760ccc842db2a50d3c2013321aa52 100644 (file)
@@ -37,10 +37,12 @@ static const struct apic apic_numachip;
 static unsigned int get_apic_id(unsigned long x)
 {
        unsigned long value;
-       unsigned int id;
+       unsigned int id = (x >> 24) & 0xff;
 
-       rdmsrl(MSR_FAM10H_NODE_ID, value);
-       id = ((x >> 24) & 0xffU) | ((value << 2) & 0xff00U);
+       if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+               rdmsrl(MSR_FAM10H_NODE_ID, value);
+               id |= (value << 2) & 0xff00;
+       }
 
        return id;
 }
@@ -155,10 +157,18 @@ static int __init numachip_probe(void)
 
 static void fixup_cpu_id(struct cpuinfo_x86 *c, int node)
 {
-       if (c->phys_proc_id != node) {
-               c->phys_proc_id = node;
-               per_cpu(cpu_llc_id, smp_processor_id()) = node;
+       u64 val;
+       u32 nodes = 1;
+
+       this_cpu_write(cpu_llc_id, node);
+
+       /* Account for nodes per socket in multi-core-module processors */
+       if (static_cpu_has_safe(X86_FEATURE_NODEID_MSR)) {
+               rdmsrl(MSR_FAM10H_NODE_ID, val);
+               nodes = ((val >> 3) & 7) + 1;
        }
+
+       c->phys_proc_id = node / nodes;
 }
 
 static int __init numachip_system_init(void)
index b5c8ff5e9dfcad79075a1af5f41b0ac0ee37231b..2346c95c6ab1945077fdde28c129342ffe09749d 100644 (file)
@@ -1396,6 +1396,12 @@ void cpu_init(void)
 
        wait_for_master_cpu(cpu);
 
+       /*
+        * Initialize the CR4 shadow before doing anything that could
+        * try to read it.
+        */
+       cr4_init_shadow();
+
        show_ucode_info_early();
 
        printk(KERN_INFO "Initializing CPU#%d\n", cpu);
index 94d7dcb1214530dfa86b4fef2f2bcbf007d32fe4..50163fa9034f0d2f4db28767432a249ad9e0cb35 100644 (file)
@@ -565,8 +565,8 @@ static const struct _tlb_table intel_tlb_table[] = {
        { 0xb2, TLB_INST_4K,            64,     " TLB_INST 4KByte pages, 4-way set associative" },
        { 0xb3, TLB_DATA_4K,            128,    " TLB_DATA 4 KByte pages, 4-way set associative" },
        { 0xb4, TLB_DATA_4K,            256,    " TLB_DATA 4 KByte pages, 4-way associative" },
-       { 0xb5, TLB_INST_4K,            64,     " TLB_INST 4 KByte pages, 8-way set ssociative" },
-       { 0xb6, TLB_INST_4K,            128,    " TLB_INST 4 KByte pages, 8-way set ssociative" },
+       { 0xb5, TLB_INST_4K,            64,     " TLB_INST 4 KByte pages, 8-way set associative" },
+       { 0xb6, TLB_INST_4K,            128,    " TLB_INST 4 KByte pages, 8-way set associative" },
        { 0xba, TLB_DATA_4K,            64,     " TLB_DATA 4 KByte pages, 4-way associative" },
        { 0xc0, TLB_DATA_4K_4M,         8,      " TLB_DATA 4 KByte and 4 MByte pages, 4-way associative" },
        { 0xc1, STLB_4K_2M,             1024,   " STLB 4 KByte and 2 MByte pages, 8-way associative" },
index 498b6d967138b1fff29659e81813c77e70ff1f58..258990688a5e999557de7f3b5398d7eccdc45ebb 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 000d4199b03e69905527d7972ccd918835e6cc1f..31e2d5bf3e38887ca06402bff6c647b9aa9a3c5c 100644 (file)
@@ -982,6 +982,9 @@ ENTRY(xen_hypervisor_callback)
 ENTRY(xen_do_upcall)
 1:     mov %esp, %eax
        call xen_evtchn_do_upcall
+#ifndef CONFIG_PREEMPT
+       call xen_maybe_preempt_hcall
+#endif
        jmp  ret_from_intr
        CFI_ENDPROC
 ENDPROC(xen_hypervisor_callback)
index db13655c3a2aff4a4475a9adf6ce1cb5b3639220..f0095a76c18211813d711bfa52b82c916190f42d 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 7ec1d5f8d28339bce0b74191a1d458c6c8e5d5df..25ecd56cefa8f22496153cf29b763c266bd8d91e 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 6a1146ea4d4d885dfa197e4d6aea6562c5d05c7e..4e3d5a9621fe0052fac43d5ad6c109b9d3f54447 100644 (file)
@@ -223,27 +223,48 @@ static unsigned long
 __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
 {
        struct kprobe *kp;
+       unsigned long faddr;
 
        kp = get_kprobe((void *)addr);
-       /* There is no probe, return original address */
-       if (!kp)
+       faddr = ftrace_location(addr);
+       /*
+        * Addresses inside the ftrace location are refused by
+        * arch_check_ftrace_location(). Something went terribly wrong
+        * if such an address is checked here.
+        */
+       if (WARN_ON(faddr && faddr != addr))
+               return 0UL;
+       /*
+        * Use the current code if it is not modified by Kprobe
+        * and it cannot be modified by ftrace.
+        */
+       if (!kp && !faddr)
                return addr;
 
        /*
-        *  Basically, kp->ainsn.insn has an original instruction.
-        *  However, RIP-relative instruction can not do single-stepping
-        *  at different place, __copy_instruction() tweaks the displacement of
-        *  that instruction. In that case, we can't recover the instruction
-        *  from the kp->ainsn.insn.
+        * Basically, kp->ainsn.insn has an original instruction.
+        * However, RIP-relative instruction can not do single-stepping
+        * at different place, __copy_instruction() tweaks the displacement of
+        * that instruction. In that case, we can't recover the instruction
+        * from the kp->ainsn.insn.
         *
-        *  On the other hand, kp->opcode has a copy of the first byte of
-        *  the probed instruction, which is overwritten by int3. And
-        *  the instruction at kp->addr is not modified by kprobes except
-        *  for the first byte, we can recover the original instruction
-        *  from it and kp->opcode.
+        * On the other hand, in case on normal Kprobe, kp->opcode has a copy
+        * of the first byte of the probed instruction, which is overwritten
+        * by int3. And the instruction at kp->addr is not modified by kprobes
+        * except for the first byte, we can recover the original instruction
+        * from it and kp->opcode.
+        *
+        * In case of Kprobes using ftrace, we do not have a copy of
+        * the original instruction. In fact, the ftrace location might
+        * be modified at anytime and even could be in an inconsistent state.
+        * Fortunately, we know that the original code is the ideal 5-byte
+        * long NOP.
         */
-       memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
-       buf[0] = kp->opcode;
+       memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+       if (faddr)
+               memcpy(buf, ideal_nops[NOP_ATOMIC5], 5);
+       else
+               buf[0] = kp->opcode;
        return (unsigned long)buf;
 }
 
@@ -251,6 +272,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
  * Recover the probed instruction at addr for further analysis.
  * Caller must lock kprobes by kprobe_mutex, or disable preemption
  * for preventing to release referencing kprobes.
+ * Returns zero if the instruction can not get recovered.
  */
 unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
 {
@@ -285,6 +307,8 @@ static int can_probe(unsigned long paddr)
                 * normally used, we just go through if there is no kprobe.
                 */
                __addr = recover_probed_instruction(buf, addr);
+               if (!__addr)
+                       return 0;
                kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE);
                insn_get_length(&insn);
 
@@ -333,6 +357,8 @@ int __copy_instruction(u8 *dest, u8 *src)
        unsigned long recovered_insn =
                recover_probed_instruction(buf, (unsigned long)src);
 
+       if (!recovered_insn)
+               return 0;
        kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
        insn_get_length(&insn);
        /* Another subsystem puts a breakpoint, failed to recover */
index 0dd8d089c315e0e9df338e9144799c6e900df831..7b3b9d15c47a63953d6932026cc57db795e3a507 100644 (file)
@@ -259,6 +259,8 @@ static int can_optimize(unsigned long paddr)
                         */
                        return 0;
                recovered_insn = recover_probed_instruction(buf, addr);
+               if (!recovered_insn)
+                       return 0;
                kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
                insn_get_length(&insn);
                /* Another subsystem puts a breakpoint */
index 9bbb9b35c144a4f721ed4e7dcfc07aee6abdc2cb..d1ac80b72c72184a0b999c2b299b5e265d26de7a 100644 (file)
@@ -47,13 +47,21 @@ do {                                                        \
 
 #ifdef CONFIG_RANDOMIZE_BASE
 static unsigned long module_load_offset;
+static int randomize_modules = 1;
 
 /* Mutex protects the module_load_offset. */
 static DEFINE_MUTEX(module_kaslr_mutex);
 
+static int __init parse_nokaslr(char *p)
+{
+       randomize_modules = 0;
+       return 0;
+}
+early_param("nokaslr", parse_nokaslr);
+
 static unsigned long int get_module_load_offset(void)
 {
-       if (kaslr_enabled) {
+       if (randomize_modules) {
                mutex_lock(&module_kaslr_mutex);
                /*
                 * Calculate the module_load_offset the first time this
index bae6c609888e7fdff25784d5bd96fd8dcd5ea88a..86db4bcd7ce52bcb74a5bf42efcd8e7152488cf1 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 98dc9317286e1e0fad25f3d10efaa3134a9134c0..0a2421cca01fad095bbb7caa8e7c779d910d751b 100644 (file)
 unsigned long max_low_pfn_mapped;
 unsigned long max_pfn_mapped;
 
-bool __read_mostly kaslr_enabled = false;
-
 #ifdef CONFIG_DMI
 RESERVE_BRK(dmi_alloc, 65536);
 #endif
@@ -427,11 +425,6 @@ static void __init reserve_initrd(void)
 }
 #endif /* CONFIG_BLK_DEV_INITRD */
 
-static void __init parse_kaslr_setup(u64 pa_data, u32 data_len)
-{
-       kaslr_enabled = (bool)(pa_data + sizeof(struct setup_data));
-}
-
 static void __init parse_setup_data(void)
 {
        struct setup_data *data;
@@ -457,9 +450,6 @@ static void __init parse_setup_data(void)
                case SETUP_EFI:
                        parse_efi_setup(pa_data, data_len);
                        break;
-               case SETUP_KASLR:
-                       parse_kaslr_setup(pa_data, data_len);
-                       break;
                default:
                        break;
                }
@@ -842,14 +832,10 @@ static void __init trim_low_memory_range(void)
 static int
 dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
 {
-       if (kaslr_enabled)
-               pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n",
-                        (unsigned long)&_text - __START_KERNEL,
-                        __START_KERNEL,
-                        __START_KERNEL_map,
-                        MODULES_VADDR-1);
-       else
-               pr_emerg("Kernel Offset: disabled\n");
+       pr_emerg("Kernel Offset: 0x%lx from 0x%lx "
+                "(relocation range: 0x%lx-0x%lx)\n",
+                (unsigned long)&_text - __START_KERNEL, __START_KERNEL,
+                __START_KERNEL_map, MODULES_VADDR-1);
 
        return 0;
 }
index 9d2073e2ecc92f5c97d51178236d8b2bc63ac029..4ff5d162ff9fd55381259ff8dd96f84064ecea72 100644 (file)
@@ -384,7 +384,7 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
                goto exit;
        conditional_sti(regs);
 
-       if (!user_mode(regs))
+       if (!user_mode_vm(regs))
                die("bounds", regs, error_code);
 
        if (!cpu_feature_enabled(X86_FEATURE_MPX)) {
@@ -637,7 +637,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
         * then it's very likely the result of an icebp/int01 trap.
         * User wants a sigtrap for that.
         */
-       if (!dr6 && user_mode(regs))
+       if (!dr6 && user_mode_vm(regs))
                user_icebp = 1;
 
        /* Catch kmemcheck conditions first of all! */
index 34f66e58a896693d392e4ed074b1f9ca664974d3..cdc6cf90307800abb83f1b4b516ba389212c3dd0 100644 (file)
@@ -379,7 +379,7 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                 * thread's fpu state, reconstruct fxstate from the fsave
                 * header. Sanitize the copied state etc.
                 */
-               struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
+               struct fpu *fpu = &tsk->thread.fpu;
                struct user_i387_ia32_struct env;
                int err = 0;
 
@@ -393,14 +393,15 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                 */
                drop_fpu(tsk);
 
-               if (__copy_from_user(xsave, buf_fx, state_size) ||
+               if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) ||
                    __copy_from_user(&env, buf, sizeof(env))) {
+                       fpu_finit(fpu);
                        err = -1;
                } else {
                        sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
-                       set_used_math();
                }
 
+               set_used_math();
                if (use_eager_fpu()) {
                        preempt_disable();
                        math_state_restore();
index e0b794a84c35cdd7ecc03bc6de6500b0ac237f57..106c01557f2b63706eca28e462a3b072b590f0c5 100644 (file)
@@ -4950,7 +4950,8 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
                        goto done;
                }
        }
-       ctxt->dst.orig_val = ctxt->dst.val;
+       /* Copy full 64-bit value for CMPXCHG8B.  */
+       ctxt->dst.orig_val64 = ctxt->dst.val64;
 
 special_insn:
 
index cc31f7c06d3ddc8ab4ef61c775510e2dcbfde518..9541ba34126b90123ddfe383453145ddfcf789c4 100644 (file)
@@ -507,6 +507,7 @@ static int picdev_read(struct kvm_pic *s,
                return -EOPNOTSUPP;
 
        if (len != 1) {
+               memset(val, 0, len);
                pr_pic_unimpl("non byte read\n");
                return 0;
        }
index b1947e0f3e100d7552add9688125d9c86d29a8ab..46d4449772bc714daa658ea6424fb45659095c70 100644 (file)
@@ -422,6 +422,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
                        struct kvm_ioapic *ioapic, int vector, int trigger_mode)
 {
        int i;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        for (i = 0; i < IOAPIC_NUM_PINS; i++) {
                union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
@@ -443,7 +444,8 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
                kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
                spin_lock(&ioapic->lock);
 
-               if (trigger_mode != IOAPIC_LEVEL_TRIG)
+               if (trigger_mode != IOAPIC_LEVEL_TRIG ||
+                   kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
                        continue;
 
                ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
index e55b5fc344eb911a7b4ed0c490d50a6767532d27..4ee827d7bf36f730c25d358f709aa99cda93260a 100644 (file)
@@ -833,8 +833,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 
 static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
 {
-       if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
-           kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
+       if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
                int trigger_mode;
                if (apic_test_vector(vector, apic->regs + APIC_TMR))
                        trigger_mode = IOAPIC_LEVEL_TRIG;
@@ -1572,7 +1571,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
                apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
        }
        apic->irr_pending = kvm_apic_vid_enabled(vcpu->kvm);
-       apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm);
+       apic->isr_count = kvm_x86_ops->hwapic_isr_update ? 1 : 0;
        apic->highest_isr_cache = -1;
        update_divide_count(apic);
        atomic_set(&apic->lapic_timer.pending, 0);
@@ -1782,7 +1781,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
        update_divide_count(apic);
        start_apic_timer(apic);
        apic->irr_pending = true;
-       apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm) ?
+       apic->isr_count = kvm_x86_ops->hwapic_isr_update ?
                                1 : count_vectors(apic->regs + APIC_ISR);
        apic->highest_isr_cache = -1;
        if (kvm_x86_ops->hwapic_irr_update)
index d319e0c24758876178aeab46c65fe611cb02126e..cc618c882f900ad21cb4de57d94daa91a5f4ec4c 100644 (file)
@@ -3649,11 +3649,6 @@ static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
        return;
 }
 
-static void svm_hwapic_isr_update(struct kvm *kvm, int isr)
-{
-       return;
-}
-
 static void svm_sync_pir_to_irr(struct kvm_vcpu *vcpu)
 {
        return;
@@ -4403,7 +4398,6 @@ static struct kvm_x86_ops svm_x86_ops = {
        .set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
        .vm_has_apicv = svm_vm_has_apicv,
        .load_eoi_exitmap = svm_load_eoi_exitmap,
-       .hwapic_isr_update = svm_hwapic_isr_update,
        .sync_pir_to_irr = svm_sync_pir_to_irr,
 
        .set_tss_addr = svm_set_tss_addr,
index 14c1a18d206aeee0d59637162b0f1a58056c8941..ae4f6d35d19c268315745741150dd6d1a7df5222 100644 (file)
@@ -2168,7 +2168,10 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
 {
        unsigned long *msr_bitmap;
 
-       if (irqchip_in_kernel(vcpu->kvm) && apic_x2apic_mode(vcpu->arch.apic)) {
+       if (is_guest_mode(vcpu))
+               msr_bitmap = vmx_msr_bitmap_nested;
+       else if (irqchip_in_kernel(vcpu->kvm) &&
+               apic_x2apic_mode(vcpu->arch.apic)) {
                if (is_long_mode(vcpu))
                        msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
                else
@@ -2476,8 +2479,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        if (enable_ept) {
                /* nested EPT: emulate EPT also to L1 */
                vmx->nested.nested_vmx_secondary_ctls_high |=
-                       SECONDARY_EXEC_ENABLE_EPT |
-                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+                       SECONDARY_EXEC_ENABLE_EPT;
                vmx->nested.nested_vmx_ept_caps = VMX_EPT_PAGE_WALK_4_BIT |
                         VMX_EPTP_WB_BIT | VMX_EPT_2MB_PAGE_BIT |
                         VMX_EPT_INVEPT_BIT;
@@ -2491,6 +2493,10 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        } else
                vmx->nested.nested_vmx_ept_caps = 0;
 
+       if (enable_unrestricted_guest)
+               vmx->nested.nested_vmx_secondary_ctls_high |=
+                       SECONDARY_EXEC_UNRESTRICTED_GUEST;
+
        /* miscellaneous data */
        rdmsr(MSR_IA32_VMX_MISC,
                vmx->nested.nested_vmx_misc_low,
@@ -4367,6 +4373,18 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_SMP
+       if (vcpu->mode == IN_GUEST_MODE) {
+               apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
+                               POSTED_INTR_VECTOR);
+               return true;
+       }
+#endif
+       return false;
+}
+
 static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
                                                int vector)
 {
@@ -4375,9 +4393,7 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
        if (is_guest_mode(vcpu) &&
            vector == vmx->nested.posted_intr_nv) {
                /* the PIR and ON have been set by L1. */
-               if (vcpu->mode == IN_GUEST_MODE)
-                       apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
-                               POSTED_INTR_VECTOR);
+               kvm_vcpu_trigger_posted_interrupt(vcpu);
                /*
                 * If a posted intr is not recognized by hardware,
                 * we will accomplish it in the next vmentry.
@@ -4409,12 +4425,7 @@ static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
 
        r = pi_test_and_set_on(&vmx->pi_desc);
        kvm_make_request(KVM_REQ_EVENT, vcpu);
-#ifdef CONFIG_SMP
-       if (!r && (vcpu->mode == IN_GUEST_MODE))
-               apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
-                               POSTED_INTR_VECTOR);
-       else
-#endif
+       if (r || !kvm_vcpu_trigger_posted_interrupt(vcpu))
                kvm_vcpu_kick(vcpu);
 }
 
@@ -9213,9 +9224,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        }
 
        if (cpu_has_vmx_msr_bitmap() &&
-           exec_control & CPU_BASED_USE_MSR_BITMAPS &&
-           nested_vmx_merge_msr_bitmap(vcpu, vmcs12)) {
-               vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_nested));
+           exec_control & CPU_BASED_USE_MSR_BITMAPS) {
+               nested_vmx_merge_msr_bitmap(vcpu, vmcs12);
+               /* MSR_BITMAP will be set by following vmx_set_efer. */
        } else
                exec_control &= ~CPU_BASED_USE_MSR_BITMAPS;
 
index bd7a70be41b35fa93ad952060fc2c7f432e5628e..32bf19ef3115f65c9dffc23a655be2763babcaff 100644 (file)
@@ -2744,7 +2744,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_USER_NMI:
        case KVM_CAP_REINJECT_CONTROL:
        case KVM_CAP_IRQ_INJECT_STATUS:
-       case KVM_CAP_IRQFD:
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_IOEVENTFD_NO_LENGTH:
        case KVM_CAP_PIT2:
index 4a0890f815c40dc2641d092ff7aeaee5cb6f0039..08f41caada45fae631599fde62f9b0d43902b7cd 100644 (file)
@@ -1,6 +1,6 @@
 config LGUEST_GUEST
        bool "Lguest guest support"
-       depends on X86_32 && PARAVIRT
+       depends on X86_32 && PARAVIRT && PCI
        select TTY
        select VIRTUALIZATION
        select VIRTIO
@@ -8,7 +8,7 @@ config LGUEST_GUEST
        help
          Lguest is a tiny in-kernel hypervisor.  Selecting this will
          allow your kernel to boot under lguest.  This option will increase
-         your kernel size by about 6k.  If in doubt, say N.
+         your kernel size by about 10k.  If in doubt, say N.
 
          If you say Y here, make sure you say Y (or M) to the virtio block
          and net drivers which lguest needs.
index 6ac273832f284635ac1a66bf3f8551de379fa0f0..e4695985f9de85778db5e084b37eda5719d3a82a 100644 (file)
@@ -331,7 +331,7 @@ static void probe_pci_root_info(struct pci_root_info *info,
                                struct list_head *list)
 {
        int ret;
-       struct resource_entry *entry;
+       struct resource_entry *entry, *tmp;
 
        sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
        info->bridge = device;
@@ -345,8 +345,13 @@ static void probe_pci_root_info(struct pci_root_info *info,
                dev_dbg(&device->dev,
                        "no IO and memory resources present in _CRS\n");
        else
-               resource_list_for_each_entry(entry, list)
-                       entry->res->name = info->name;
+               resource_list_for_each_entry_safe(entry, tmp, list) {
+                       if ((entry->res->flags & IORESOURCE_WINDOW) == 0 ||
+                           (entry->res->flags & IORESOURCE_DISABLED))
+                               resource_list_destroy_entry(entry);
+                       else
+                               entry->res->name = info->name;
+               }
 }
 
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
index 3d2612b68694efd294ca214d478c7777030f4b03..2fb384724ebb52d1cf0ba6131b418e81609ca55c 100644 (file)
@@ -513,31 +513,6 @@ void __init pcibios_set_cache_line_size(void)
        }
 }
 
-/*
- * Some device drivers assume dev->irq won't change after calling
- * pci_disable_device(). So delay releasing of IRQ resource to driver
- * unbinding time. Otherwise it will break PM subsystem and drivers
- * like xen-pciback etc.
- */
-static int pci_irq_notifier(struct notifier_block *nb, unsigned long action,
-                           void *data)
-{
-       struct pci_dev *dev = to_pci_dev(data);
-
-       if (action != BUS_NOTIFY_UNBOUND_DRIVER)
-               return NOTIFY_DONE;
-
-       if (pcibios_disable_irq)
-               pcibios_disable_irq(dev);
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block pci_irq_nb = {
-       .notifier_call = pci_irq_notifier,
-       .priority = INT_MIN,
-};
-
 int __init pcibios_init(void)
 {
        if (!raw_pci_ops) {
@@ -550,9 +525,6 @@ int __init pcibios_init(void)
 
        if (pci_bf_sort >= pci_force_bf)
                pci_sort_breadthfirst();
-
-       bus_register_notifier(&pci_bus_type, &pci_irq_nb);
-
        return 0;
 }
 
@@ -711,6 +683,12 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return 0;
 }
 
+void pcibios_disable_device (struct pci_dev *dev)
+{
+       if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
+               pcibios_disable_irq(dev);
+}
+
 int pci_ext_cfg_avail(void)
 {
        if (raw_pci_ext_ops)
index efb849323c745899f5e665364ceec36a1d15cb9d..852aa4c92da027cb07fb64c77c855aaf0877a1da 100644 (file)
@@ -234,10 +234,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 
 static void intel_mid_pci_irq_disable(struct pci_dev *dev)
 {
-       if (dev->irq_managed && dev->irq > 0) {
+       if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
+           dev->irq > 0) {
                mp_unmap_irq(dev->irq);
                dev->irq_managed = 0;
-               dev->irq = 0;
        }
 }
 
index e71b3dbd87b8f688d3f2cbfa995421bd516ba581..5dc6ca5e174131d2c7208ea1ed86739ef4532d22 100644 (file)
@@ -1256,9 +1256,22 @@ static int pirq_enable_irq(struct pci_dev *dev)
        return 0;
 }
 
+bool mp_should_keep_irq(struct device *dev)
+{
+       if (dev->power.is_prepared)
+               return true;
+#ifdef CONFIG_PM
+       if (dev->power.runtime_status == RPM_SUSPENDING)
+               return true;
+#endif
+
+       return false;
+}
+
 static void pirq_disable_irq(struct pci_dev *dev)
 {
-       if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) {
+       if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
+           dev->irq_managed && dev->irq) {
                mp_unmap_irq(dev->irq);
                dev->irq = 0;
                dev->irq_managed = 0;
index 1bbedc4b0f88d46bee5000779c4ef5aa4e4d0411..3005f0c89f2ecfbcc817c7e379c97586d5524e7f 100644 (file)
@@ -130,7 +130,7 @@ static void intel_mid_arch_setup(void)
                intel_mid_ops = get_intel_mid_ops[__intel_mid_cpu_chip]();
        else {
                intel_mid_ops = get_intel_mid_ops[INTEL_MID_CPU_CHIP_PENWELL]();
-               pr_info("ARCH: Uknown SoC, assuming PENWELL!\n");
+               pr_info("ARCH: Unknown SoC, assuming PENWELL!\n");
        }
 
 out:
index 31776d0efc8c40fa0aa6989731b1ddf23229029c..d7ec4e251c0a2e53572438891508dfeb4a3a016a 100644 (file)
@@ -17,6 +17,7 @@
        .text
        .globl __kernel_sigreturn
        .type __kernel_sigreturn,@function
+       nop /* this guy is needed for .LSTARTFDEDLSI1 below (watch for HACK) */
        ALIGN
 __kernel_sigreturn:
 .LSTART_sigreturn:
index bd8b8459c3d05923286b4dc6b5ebb7e37e51d926..5240f563076de2e0e27c92af2d04ad03d213ee8f 100644 (file)
@@ -1070,6 +1070,23 @@ static inline void xen_write_cr8(unsigned long val)
        BUG_ON(val);
 }
 #endif
+
+static u64 xen_read_msr_safe(unsigned int msr, int *err)
+{
+       u64 val;
+
+       val = native_read_msr_safe(msr, err);
+       switch (msr) {
+       case MSR_IA32_APICBASE:
+#ifdef CONFIG_X86_X2APIC
+               if (!(cpuid_ecx(1) & (1 << (X86_FEATURE_X2APIC & 31))))
+#endif
+                       val &= ~X2APIC_ENABLE;
+               break;
+       }
+       return val;
+}
+
 static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
 {
        int ret;
@@ -1240,7 +1257,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
 
        .wbinvd = native_wbinvd,
 
-       .read_msr = native_read_msr_safe,
+       .read_msr = xen_read_msr_safe,
        .write_msr = xen_write_msr_safe,
 
        .read_tsc = native_read_tsc,
@@ -1741,6 +1758,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
 #ifdef CONFIG_X86_32
        i386_start_kernel();
 #else
+       cr4_init_shadow(); /* 32b kernel does this in i386_start_kernel() */
        x86_64_start_reservations((char *)__pa_symbol(&boot_params));
 #endif
 }
index 740ae3026a148ec54800710427a455dc890351d3..b47124d4cd67e29199fae1c48f9a94ecd93b00f7 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 fc1ff3b1ea1f4a9ea2dcd18d6e49eea7281eb9b3..fd3fee81c23ce2f1cdc73d2bf4e76188c90358cb 100644 (file)
@@ -592,7 +592,7 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
        if (q->queue_flags & (1 << QUEUE_FLAG_SG_GAPS)) {
                struct bio_vec *bprev;
 
-               bprev = &rq->biotail->bi_io_vec[bio->bi_vcnt - 1];
+               bprev = &rq->biotail->bi_io_vec[rq->biotail->bi_vcnt - 1];
                if (bvec_gap_to_prev(bprev, bio->bi_io_vec[0].bv_offset))
                        return false;
        }
index d53a764b05eacde776a4454054795d1c0277d676..be3290cc0644efc9e3feec6fd891c7afe1a15775 100644 (file)
@@ -278,9 +278,11 @@ static int bt_get(struct blk_mq_alloc_data *data,
                /*
                 * We're out of tags on this hardware queue, kick any
                 * pending IO submits before going to sleep waiting for
-                * some to complete.
+                * some to complete. Note that hctx can be NULL here for
+                * reserved tag allocation.
                 */
-               blk_mq_run_hw_queue(hctx, false);
+               if (hctx)
+                       blk_mq_run_hw_queue(hctx, false);
 
                /*
                 * Retry tag allocation after running the hardware queue,
index 4f4bea21052e41068112ead8cbb4e0a42cb7a9d6..b7b8933ec24188b2807229af1aa844503b46dc89 100644 (file)
@@ -1938,7 +1938,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
         */
        if (percpu_ref_init(&q->mq_usage_counter, blk_mq_usage_counter_release,
                            PERCPU_REF_INIT_ATOMIC, GFP_KERNEL))
-               goto err_map;
+               goto err_mq_usage;
 
        setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q);
        blk_queue_rq_timeout(q, 30000);
@@ -1981,7 +1981,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
        blk_mq_init_cpu_queues(q, set->nr_hw_queues);
 
        if (blk_mq_init_hw_queues(q, set))
-               goto err_hw;
+               goto err_mq_usage;
 
        mutex_lock(&all_q_mutex);
        list_add_tail(&q->all_q_node, &all_q_list);
@@ -1993,7 +1993,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
 
        return q;
 
-err_hw:
+err_mq_usage:
        blk_cleanup_queue(q);
 err_hctxs:
        kfree(map);
index 6ed2cbe5e8c9ae340233b0491255dfed40947590..12600bfffca93f4547e2325eeda9669ff443a7a7 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 657964e8ab7ed2ba9e56004d5f83881ad826e7b7..37fb1904760396751f27778e819d90c0fd9af83b 100644 (file)
@@ -65,6 +65,7 @@ struct lpss_private_data;
 
 struct lpss_device_desc {
        unsigned int flags;
+       const char *clk_con_id;
        unsigned int prv_offset;
        size_t prv_size_override;
        void (*setup)(struct lpss_private_data *pdata);
@@ -140,6 +141,7 @@ static struct lpss_device_desc lpt_i2c_dev_desc = {
 
 static struct lpss_device_desc lpt_uart_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
+       .clk_con_id = "baudclk",
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
@@ -156,6 +158,7 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
 
 static struct lpss_device_desc byt_uart_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+       .clk_con_id = "baudclk",
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
@@ -313,7 +316,7 @@ out:
                return PTR_ERR(clk);
 
        pdata->clk = clk;
-       clk_register_clkdev(clk, NULL, devname);
+       clk_register_clkdev(clk, dev_desc->clk_con_id, devname);
        return 0;
 }
 
index e7f718d6918a6a29b775aa97f7a40dc654d47136..b1def411c0b89cbf7847b767063c5c2ab528e8a8 100644 (file)
@@ -485,6 +485,14 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        if (!pin || !dev->irq_managed || dev->irq <= 0)
                return;
 
+       /* Keep IOAPIC pin configuration when suspending */
+       if (dev->dev.power.is_prepared)
+               return;
+#ifdef CONFIG_PM
+       if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+               return;
+#endif
+
        entry = acpi_pci_irq_lookup(dev, pin);
        if (!entry)
                return;
@@ -505,6 +513,5 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        if (gsi >= 0) {
                acpi_unregister_gsi(gsi);
                dev->irq_managed = 0;
-               dev->irq = 0;
        }
 }
index c723668e3e277def6f8d6309fe1af21b989951fb..5589a6e2a02346e3b2ce48656b3facea1abfc621 100644 (file)
@@ -42,8 +42,10 @@ static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
         * CHECKME: len might be required to check versus a minimum
         * length as well. 1 for io is fine, but for memory it does
         * not make any sense at all.
+        * Note: some BIOSes report incorrect length for ACPI address space
+        * descriptor, so remove check of 'reslen == len' to avoid regression.
         */
-       if (len && reslen && reslen == len && start <= end)
+       if (len && reslen && start <= end)
                return true;
 
        pr_debug("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n",
index debd30917010a17697102bc84d1e468c69c94d17..26eb70c8f5184f878ae489c4130e1b382d7394a2 100644 (file)
@@ -2110,7 +2110,8 @@ static int __init intel_opregion_present(void)
 
 int acpi_video_register(void)
 {
-       int result = 0;
+       int ret;
+
        if (register_count) {
                /*
                 * if the function of acpi_video_register is already called,
@@ -2122,9 +2123,9 @@ int acpi_video_register(void)
        mutex_init(&video_list_lock);
        INIT_LIST_HEAD(&video_bus_head);
 
-       result = acpi_bus_register_driver(&acpi_video_bus);
-       if (result < 0)
-               return -ENODEV;
+       ret = acpi_bus_register_driver(&acpi_video_bus);
+       if (ret)
+               return ret;
 
        /*
         * When the acpi_video_bus is loaded successfully, increase
@@ -2176,6 +2177,17 @@ EXPORT_SYMBOL(acpi_video_unregister_backlight);
 
 static int __init acpi_video_init(void)
 {
+       /*
+        * Let the module load even if ACPI is disabled (e.g. due to
+        * a broken BIOS) so that i915.ko can still be loaded on such
+        * old systems without an AcpiOpRegion.
+        *
+        * acpi_video_register() will report -ENODEV later as well due
+        * to acpi_disabled when i915.ko tries to register itself afterwards.
+        */
+       if (acpi_disabled)
+               return 0;
+
        dmi_check_system(video_dmi_table);
 
        if (intel_opregion_present())
index 33b09b6568a4a464657b51667ffe8596c7893b2f..6607f3c6ace1033fd4ca449d579bd2b7638e3963 100644 (file)
@@ -551,7 +551,6 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
 {
        void *page_addr;
        unsigned long user_page_addr;
-       struct vm_struct tmp_area;
        struct page **page;
        struct mm_struct *mm;
 
@@ -600,10 +599,11 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
                                proc->pid, page_addr);
                        goto err_alloc_page_failed;
                }
-               tmp_area.addr = page_addr;
-               tmp_area.size = PAGE_SIZE + PAGE_SIZE /* guard page? */;
-               ret = map_vm_area(&tmp_area, PAGE_KERNEL, page);
-               if (ret) {
+               ret = map_kernel_range_noflush((unsigned long)page_addr,
+                                       PAGE_SIZE, PAGE_KERNEL, page);
+               flush_cache_vmap((unsigned long)page_addr,
+                               (unsigned long)page_addr + PAGE_SIZE);
+               if (ret != 1) {
                        pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n",
                               proc->pid, page_addr);
                        goto err_map_kernel_failed;
index 4c35f0822d06e54dd5399a285d22cbcfe174b115..23dac3babfe3afc710db73a2ad4f8fe05174b7d7 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 f9054cd36a7266bbed21db2503a63672d0d8040c..5389579c51204cf336f2689052ccf29c48b8af98 100644 (file)
@@ -869,6 +869,8 @@ try_offline_again:
         */
        ata_msleep(ap, 1);
 
+       sata_set_spd(link);
+
        /*
         * Now, bring the host controller online again, this can take time
         * as PHY reset and communication establishment, 1st D2H FIS and
index ba4abbe4693c3e29be764d66662295dd300d41c4..45937f88e77c88893f6f05430efcd2dd88449e9f 100644 (file)
@@ -2242,7 +2242,7 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
 }
 
 static int pm_genpd_summary_one(struct seq_file *s,
-               struct generic_pm_domain *gpd)
+                               struct generic_pm_domain *genpd)
 {
        static const char * const status_lookup[] = {
                [GPD_STATE_ACTIVE] = "on",
@@ -2256,26 +2256,26 @@ static int pm_genpd_summary_one(struct seq_file *s,
        struct gpd_link *link;
        int ret;
 
-       ret = mutex_lock_interruptible(&gpd->lock);
+       ret = mutex_lock_interruptible(&genpd->lock);
        if (ret)
                return -ERESTARTSYS;
 
-       if (WARN_ON(gpd->status >= ARRAY_SIZE(status_lookup)))
+       if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
                goto exit;
-       seq_printf(s, "%-30s  %-15s  ", gpd->name, status_lookup[gpd->status]);
+       seq_printf(s, "%-30s  %-15s  ", genpd->name, status_lookup[genpd->status]);
 
        /*
         * Modifications on the list require holding locks on both
         * master and slave, so we are safe.
-        * Also gpd->name is immutable.
+        * Also genpd->name is immutable.
         */
-       list_for_each_entry(link, &gpd->master_links, master_node) {
+       list_for_each_entry(link, &genpd->master_links, master_node) {
                seq_printf(s, "%s", link->slave->name);
-               if (!list_is_last(&link->master_node, &gpd->master_links))
+               if (!list_is_last(&link->master_node, &genpd->master_links))
                        seq_puts(s, ", ");
        }
 
-       list_for_each_entry(pm_data, &gpd->dev_list, list_node) {
+       list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
                kobj_path = kobject_get_path(&pm_data->dev->kobj, GFP_KERNEL);
                if (kobj_path == NULL)
                        continue;
@@ -2287,14 +2287,14 @@ static int pm_genpd_summary_one(struct seq_file *s,
 
        seq_puts(s, "\n");
 exit:
-       mutex_unlock(&gpd->lock);
+       mutex_unlock(&genpd->lock);
 
        return 0;
 }
 
 static int pm_genpd_summary_show(struct seq_file *s, void *data)
 {
-       struct generic_pm_domain *gpd;
+       struct generic_pm_domain *genpd;
        int ret = 0;
 
        seq_puts(s, "    domain                      status         slaves\n");
@@ -2305,8 +2305,8 @@ static int pm_genpd_summary_show(struct seq_file *s, void *data)
        if (ret)
                return -ERESTARTSYS;
 
-       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
-               ret = pm_genpd_summary_one(s, gpd);
+       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
+               ret = pm_genpd_summary_one(s, genpd);
                if (ret)
                        break;
        }
index c2744b30d5d92e9dde512e492cf9fdf44f21b5ef..aab7158d2afea87c5cee091eb2af3a1ae0a7222a 100644 (file)
@@ -730,6 +730,7 @@ void pm_system_wakeup(void)
        pm_abort_suspend = true;
        freeze_wake();
 }
+EXPORT_SYMBOL_GPL(pm_system_wakeup);
 
 void pm_wakeup_clear(void)
 {
index beb8b27d4621a6d9f839065c1296fa8ab67f3032..a13587b5c2be32b912f9fe0fd7544761a280bd57 100644 (file)
@@ -243,4 +243,12 @@ extern struct regcache_ops regcache_rbtree_ops;
 extern struct regcache_ops regcache_lzo_ops;
 extern struct regcache_ops regcache_flat_ops;
 
+static inline const char *regmap_name(const struct regmap *map)
+{
+       if (map->dev)
+               return dev_name(map->dev);
+
+       return map->name;
+}
+
 #endif
index d453a2c98ad0a6529170dc5a8f21bab9204255f7..81751a49d8bf2334612350bba52406b9af352258 100644 (file)
@@ -307,7 +307,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
        if (pos == 0) {
                memmove(blk + offset * map->cache_word_size,
                        blk, rbnode->blklen * map->cache_word_size);
-               bitmap_shift_right(present, present, offset, blklen);
+               bitmap_shift_left(present, present, offset, blklen);
        }
 
        /* update the rbnode block, its size and the base register */
index f373c35f9e1db239874589464b6375ebfe5d769a..87db9893b463ba505acc3c28e253b5a08cf20c90 100644 (file)
@@ -218,7 +218,7 @@ int regcache_read(struct regmap *map,
                ret = map->cache_ops->read(map, reg, value);
 
                if (ret == 0)
-                       trace_regmap_reg_read_cache(map->dev, reg, *value);
+                       trace_regmap_reg_read_cache(map, reg, *value);
 
                return ret;
        }
@@ -311,7 +311,7 @@ int regcache_sync(struct regmap *map)
        dev_dbg(map->dev, "Syncing %s cache\n",
                map->cache_ops->name);
        name = map->cache_ops->name;
-       trace_regcache_sync(map->dev, name, "start");
+       trace_regcache_sync(map, name, "start");
 
        if (!map->cache_dirty)
                goto out;
@@ -346,7 +346,7 @@ out:
 
        regmap_async_complete(map);
 
-       trace_regcache_sync(map->dev, name, "stop");
+       trace_regcache_sync(map, name, "stop");
 
        return ret;
 }
@@ -381,7 +381,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
        name = map->cache_ops->name;
        dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
 
-       trace_regcache_sync(map->dev, name, "start region");
+       trace_regcache_sync(map, name, "start region");
 
        if (!map->cache_dirty)
                goto out;
@@ -401,7 +401,7 @@ out:
 
        regmap_async_complete(map);
 
-       trace_regcache_sync(map->dev, name, "stop region");
+       trace_regcache_sync(map, name, "stop region");
 
        return ret;
 }
@@ -428,7 +428,7 @@ int regcache_drop_region(struct regmap *map, unsigned int min,
 
        map->lock(map->lock_arg);
 
-       trace_regcache_drop_region(map->dev, min, max);
+       trace_regcache_drop_region(map, min, max);
 
        ret = map->cache_ops->drop(map, min, max);
 
@@ -455,7 +455,7 @@ void regcache_cache_only(struct regmap *map, bool enable)
        map->lock(map->lock_arg);
        WARN_ON(map->cache_bypass && enable);
        map->cache_only = enable;
-       trace_regmap_cache_only(map->dev, enable);
+       trace_regmap_cache_only(map, enable);
        map->unlock(map->lock_arg);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -493,7 +493,7 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
        map->lock(map->lock_arg);
        WARN_ON(map->cache_only && enable);
        map->cache_bypass = enable;
-       trace_regmap_cache_bypass(map->dev, enable);
+       trace_regmap_cache_bypass(map, enable);
        map->unlock(map->lock_arg);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@ -608,7 +608,8 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
        for (i = start; i < end; i++) {
                regtmp = block_base + (i * map->reg_stride);
 
-               if (!regcache_reg_present(cache_present, i))
+               if (!regcache_reg_present(cache_present, i) ||
+                   !regmap_writeable(map, regtmp))
                        continue;
 
                val = regcache_get_val(map, block, i);
@@ -677,7 +678,8 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
        for (i = start; i < end; i++) {
                regtmp = block_base + (i * map->reg_stride);
 
-               if (!regcache_reg_present(cache_present, i)) {
+               if (!regcache_reg_present(cache_present, i) ||
+                   !regmap_writeable(map, regtmp)) {
                        ret = regcache_sync_block_raw_flush(map, &data,
                                                            base, regtmp);
                        if (ret != 0)
index 6299a50a59607f6d5598eac804817cef47e8c106..a6c3f75b4b01e1145c6eb5bb9816182a0f9c9fde 100644 (file)
@@ -499,7 +499,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                goto err_alloc;
        }
 
-       ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
+       ret = request_threaded_irq(irq, NULL, regmap_irq_thread,
+                                  irq_flags | IRQF_ONESHOT,
                                   chip->name, d);
        if (ret != 0) {
                dev_err(map->dev, "Failed to request IRQ %d for %s: %d\n",
index f99b098ddabfbd23dae3ab3ee7733b9ff24e28ef..dbfe6a69c3daa67969df7c670f9e5144a053afb6 100644 (file)
@@ -1281,7 +1281,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
        if (map->async && map->bus->async_write) {
                struct regmap_async *async;
 
-               trace_regmap_async_write_start(map->dev, reg, val_len);
+               trace_regmap_async_write_start(map, reg, val_len);
 
                spin_lock_irqsave(&map->async_lock, flags);
                async = list_first_entry_or_null(&map->async_free,
@@ -1339,8 +1339,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                return ret;
        }
 
-       trace_regmap_hw_write_start(map->dev, reg,
-                                   val_len / map->format.val_bytes);
+       trace_regmap_hw_write_start(map, reg, val_len / map->format.val_bytes);
 
        /* If we're doing a single register write we can probably just
         * send the work_buf directly, otherwise try to do a gather
@@ -1372,8 +1371,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                kfree(buf);
        }
 
-       trace_regmap_hw_write_done(map->dev, reg,
-                                  val_len / map->format.val_bytes);
+       trace_regmap_hw_write_done(map, reg, val_len / map->format.val_bytes);
 
        return ret;
 }
@@ -1407,12 +1405,12 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
 
        map->format.format_write(map, reg, val);
 
-       trace_regmap_hw_write_start(map->dev, reg, 1);
+       trace_regmap_hw_write_start(map, reg, 1);
 
        ret = map->bus->write(map->bus_context, map->work_buf,
                              map->format.buf_size);
 
-       trace_regmap_hw_write_done(map->dev, reg, 1);
+       trace_regmap_hw_write_done(map, reg, 1);
 
        return ret;
 }
@@ -1470,7 +1468,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
                dev_info(map->dev, "%x <= %x\n", reg, val);
 #endif
 
-       trace_regmap_reg_write(map->dev, reg, val);
+       trace_regmap_reg_write(map, reg, val);
 
        return map->reg_write(context, reg, val);
 }
@@ -1773,7 +1771,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
        for (i = 0; i < num_regs; i++) {
                int reg = regs[i].reg;
                int val = regs[i].def;
-               trace_regmap_hw_write_start(map->dev, reg, 1);
+               trace_regmap_hw_write_start(map, reg, 1);
                map->format.format_reg(u8, reg, map->reg_shift);
                u8 += reg_bytes + pad_bytes;
                map->format.format_val(u8, val, 0);
@@ -1788,7 +1786,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
 
        for (i = 0; i < num_regs; i++) {
                int reg = regs[i].reg;
-               trace_regmap_hw_write_done(map->dev, reg, 1);
+               trace_regmap_hw_write_done(map, reg, 1);
        }
        return ret;
 }
@@ -2059,15 +2057,13 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
         */
        u8[0] |= map->read_flag_mask;
 
-       trace_regmap_hw_read_start(map->dev, reg,
-                                  val_len / map->format.val_bytes);
+       trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes);
 
        ret = map->bus->read(map->bus_context, map->work_buf,
                             map->format.reg_bytes + map->format.pad_bytes,
                             val, val_len);
 
-       trace_regmap_hw_read_done(map->dev, reg,
-                                 val_len / map->format.val_bytes);
+       trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes);
 
        return ret;
 }
@@ -2123,7 +2119,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
                        dev_info(map->dev, "%x => %x\n", reg, *val);
 #endif
 
-               trace_regmap_reg_read(map->dev, reg, *val);
+               trace_regmap_reg_read(map, reg, *val);
 
                if (!map->cache_bypass)
                        regcache_write(map, reg, *val);
@@ -2480,7 +2476,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
        struct regmap *map = async->map;
        bool wake;
 
-       trace_regmap_async_io_complete(map->dev);
+       trace_regmap_async_io_complete(map);
 
        spin_lock(&map->async_lock);
        list_move(&async->list, &map->async_free);
@@ -2525,7 +2521,7 @@ int regmap_async_complete(struct regmap *map)
        if (!map->bus || !map->bus->async_write)
                return 0;
 
-       trace_regmap_async_complete_start(map->dev);
+       trace_regmap_async_complete_start(map);
 
        wait_event(map->async_waitq, regmap_async_is_done(map));
 
@@ -2534,7 +2530,7 @@ int regmap_async_complete(struct regmap *map)
        map->async_ret = 0;
        spin_unlock_irqrestore(&map->async_lock, flags);
 
-       trace_regmap_async_complete_done(map->dev);
+       trace_regmap_async_complete_done(map);
 
        return ret;
 }
index 4bc2a5cb9935fbc6f5256102bdf9c2c24b9e6d8c..a98c41f72c63f4ceac0cef519f12a7b1b5be7702 100644 (file)
@@ -803,10 +803,6 @@ static int __init nbd_init(void)
                return -EINVAL;
        }
 
-       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
-       if (!nbd_dev)
-               return -ENOMEM;
-
        part_shift = 0;
        if (max_part > 0) {
                part_shift = fls(max_part);
@@ -828,6 +824,10 @@ static int __init nbd_init(void)
        if (nbds_max > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
+       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
+       if (!nbd_dev)
+               return -ENOMEM;
+
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = alloc_disk(1 << part_shift);
                if (!disk)
index b64bccbb78c9a5223548f7b7e25e33c4eb51afd4..e23be20a341752c1b175cc05612c7e087ee24fa4 100644 (file)
@@ -482,6 +482,7 @@ static int nvme_error_status(u16 status)
        }
 }
 
+#ifdef CONFIG_BLK_DEV_INTEGRITY
 static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
 {
        if (be32_to_cpu(pi->ref_tag) == v)
@@ -538,6 +539,58 @@ static void nvme_dif_remap(struct request *req,
        kunmap_atomic(pmap);
 }
 
+static int nvme_noop_verify(struct blk_integrity_iter *iter)
+{
+       return 0;
+}
+
+static int nvme_noop_generate(struct blk_integrity_iter *iter)
+{
+       return 0;
+}
+
+struct blk_integrity nvme_meta_noop = {
+       .name                   = "NVME_META_NOOP",
+       .generate_fn            = nvme_noop_generate,
+       .verify_fn              = nvme_noop_verify,
+};
+
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+       struct blk_integrity integrity;
+
+       switch (ns->pi_type) {
+       case NVME_NS_DPS_PI_TYPE3:
+               integrity = t10_pi_type3_crc;
+               break;
+       case NVME_NS_DPS_PI_TYPE1:
+       case NVME_NS_DPS_PI_TYPE2:
+               integrity = t10_pi_type1_crc;
+               break;
+       default:
+               integrity = nvme_meta_noop;
+               break;
+       }
+       integrity.tuple_size = ns->ms;
+       blk_integrity_register(ns->disk, &integrity);
+       blk_queue_max_integrity_segments(ns->queue, 1);
+}
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+static void nvme_dif_remap(struct request *req,
+                       void (*dif_swap)(u32 p, u32 v, struct t10_pi_tuple *pi))
+{
+}
+static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+}
+static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+}
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+}
+#endif
+
 static void req_completion(struct nvme_queue *nvmeq, void *ctx,
                                                struct nvme_completion *cqe)
 {
@@ -1959,43 +2012,6 @@ static void nvme_config_discard(struct nvme_ns *ns)
        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
 }
 
-static int nvme_noop_verify(struct blk_integrity_iter *iter)
-{
-       return 0;
-}
-
-static int nvme_noop_generate(struct blk_integrity_iter *iter)
-{
-       return 0;
-}
-
-struct blk_integrity nvme_meta_noop = {
-       .name                   = "NVME_META_NOOP",
-       .generate_fn            = nvme_noop_generate,
-       .verify_fn              = nvme_noop_verify,
-};
-
-static void nvme_init_integrity(struct nvme_ns *ns)
-{
-       struct blk_integrity integrity;
-
-       switch (ns->pi_type) {
-       case NVME_NS_DPS_PI_TYPE3:
-               integrity = t10_pi_type3_crc;
-               break;
-       case NVME_NS_DPS_PI_TYPE1:
-       case NVME_NS_DPS_PI_TYPE2:
-               integrity = t10_pi_type1_crc;
-               break;
-       default:
-               integrity = nvme_meta_noop;
-               break;
-       }
-       integrity.tuple_size = ns->ms;
-       blk_integrity_register(ns->disk, &integrity);
-       blk_queue_max_integrity_segments(ns->queue, 1);
-}
-
 static int nvme_revalidate_disk(struct gendisk *disk)
 {
        struct nvme_ns *ns = disk->private_data;
@@ -2036,7 +2052,8 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        pi_type = ns->ms == sizeof(struct t10_pi_tuple) ?
                                        id->dps & NVME_NS_DPS_PI_MASK : 0;
 
-       if (disk->integrity && (ns->pi_type != pi_type || ns->ms != old_ms ||
+       if (blk_get_integrity(disk) && (ns->pi_type != pi_type ||
+                               ns->ms != old_ms ||
                                bs != queue_logical_block_size(disk->queue) ||
                                (ns->ms && id->flbas & NVME_NS_FLBAS_META_EXT)))
                blk_integrity_unregister(disk);
@@ -2044,11 +2061,11 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        ns->pi_type = pi_type;
        blk_queue_logical_block_size(ns->queue, bs);
 
-       if (ns->ms && !disk->integrity && (disk->flags & GENHD_FL_UP) &&
+       if (ns->ms && !blk_get_integrity(disk) && (disk->flags & GENHD_FL_UP) &&
                                !(id->flbas & NVME_NS_FLBAS_META_EXT))
                nvme_init_integrity(ns);
 
-       if (id->ncap == 0 || (ns->ms && !disk->integrity))
+       if (id->ncap == 0 || (ns->ms && !blk_get_integrity(disk)))
                set_capacity(disk, 0);
        else
                set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
@@ -2652,7 +2669,7 @@ static void nvme_dev_remove(struct nvme_dev *dev)
 
        list_for_each_entry(ns, &dev->namespaces, list) {
                if (ns->disk->flags & GENHD_FL_UP) {
-                       if (ns->disk->integrity)
+                       if (blk_get_integrity(ns->disk))
                                blk_integrity_unregister(ns->disk);
                        del_gendisk(ns->disk);
                }
@@ -2986,6 +3003,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        get_device(dev->device);
 
+       INIT_LIST_HEAD(&dev->node);
        INIT_WORK(&dev->probe_work, nvme_async_probe);
        schedule_work(&dev->probe_work);
        return 0;
index 8e233edd7a097a0f91d323071c97f16e43308e5d..871bd3550cb0e0842296771412e749225542ffac 100644 (file)
@@ -528,7 +528,7 @@ out_cleanup:
 static inline void update_used_max(struct zram *zram,
                                        const unsigned long pages)
 {
-       int old_max, cur_max;
+       unsigned long old_max, cur_max;
 
        old_max = atomic_long_read(&zram->stats.max_used_pages);
 
index b876888811432a9bad46ab73a32ca40b04ed2ce4..8bfc4c2bba87b61f46dfbb4778463f393226f735 100644 (file)
@@ -272,6 +272,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
 
        /* Intel Bluetooth devices */
+       { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
        { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
        { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
        { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW },
index 1d278ccd751f07002e6f6c2d43ad07e030a29bff..e096e9cddb4014f6896be0341ace9ed61803da34 100644 (file)
@@ -140,24 +140,24 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
 {
        int rc;
 
-       rc = device_add(&chip->dev);
+       rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
        if (rc) {
                dev_err(&chip->dev,
-                       "unable to device_register() %s, major %d, minor %d, err=%d\n",
+                       "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
                        chip->devname, MAJOR(chip->dev.devt),
                        MINOR(chip->dev.devt), rc);
 
+               device_unregister(&chip->dev);
                return rc;
        }
 
-       rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
+       rc = device_add(&chip->dev);
        if (rc) {
                dev_err(&chip->dev,
-                       "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+                       "unable to device_register() %s, major %d, minor %d, err=%d\n",
                        chip->devname, MAJOR(chip->dev.devt),
                        MINOR(chip->dev.devt), rc);
 
-               device_unregister(&chip->dev);
                return rc;
        }
 
@@ -174,27 +174,17 @@ static void tpm_dev_del_device(struct tpm_chip *chip)
  * tpm_chip_register() - create a character device for the TPM chip
  * @chip: TPM chip to use.
  *
- * Creates a character device for the TPM chip and adds sysfs interfaces for
- * the device, PPI and TCPA. As the last step this function adds the
- * chip to the list of TPM chips available for use.
+ * Creates a character device for the TPM chip and adds sysfs attributes for
+ * the device. As the last step this function adds the chip to the list of TPM
+ * chips available for in-kernel use.
  *
- * NOTE: This function should be only called after the chip initialization
- * is complete.
- *
- * Called from tpm_<specific>.c probe function only for devices
- * the driver has determined it should claim.  Prior to calling
- * this function the specific probe function has called pci_enable_device
- * upon errant exit from this function specific probe function should call
- * pci_disable_device
+ * This function should be only called after the chip initialization is
+ * complete.
  */
 int tpm_chip_register(struct tpm_chip *chip)
 {
        int rc;
 
-       rc = tpm_dev_add_device(chip);
-       if (rc)
-               return rc;
-
        /* Populate sysfs for TPM1 devices. */
        if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
                rc = tpm_sysfs_add_device(chip);
@@ -208,6 +198,10 @@ int tpm_chip_register(struct tpm_chip *chip)
                chip->bios_dir = tpm_bios_log_setup(chip->devname);
        }
 
+       rc = tpm_dev_add_device(chip);
+       if (rc)
+               return rc;
+
        /* Make the chip available. */
        spin_lock(&driver_lock);
        list_add_rcu(&chip->list, &tpm_chip_list);
index b1e53e3aece5639e622dcced99ba2cd8396b8af7..42ffa5e7a1e0f6c912a0e214e67a3a99d1511a08 100644 (file)
@@ -124,7 +124,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
 {
        struct ibmvtpm_dev *ibmvtpm;
        struct ibmvtpm_crq crq;
-       u64 *word = (u64 *) &crq;
+       __be64 *word = (__be64 *)&crq;
        int rc;
 
        ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
@@ -145,11 +145,11 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
        memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
        crq.valid = (u8)IBMVTPM_VALID_CMD;
        crq.msg = (u8)VTPM_TPM_COMMAND;
-       crq.len = (u16)count;
-       crq.data = ibmvtpm->rtce_dma_handle;
+       crq.len = cpu_to_be16(count);
+       crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
 
-       rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]),
-                             cpu_to_be64(word[1]));
+       rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]),
+                             be64_to_cpu(word[1]));
        if (rc != H_SUCCESS) {
                dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
                rc = 0;
index f595f14426bf1fcf50f1f95f6e062b3e9fa22e22..6af92890518f8be2bed63503f6170ddbdb1476d2 100644 (file)
@@ -22,9 +22,9 @@
 struct ibmvtpm_crq {
        u8 valid;
        u8 msg;
-       u16 len;
-       u32 data;
-       u64 reserved;
+       __be16 len;
+       __be32 data;
+       __be64 reserved;
 } __attribute__((packed, aligned(8)));
 
 struct ibmvtpm_crq_queue {
index fae2dbbf57459fe4f4ac01bb0415a02abbda9e18..72d7028f779b55801795ef0fe49d9dda8cde7970 100644 (file)
@@ -142,6 +142,7 @@ struct ports_device {
         * notification
         */
        struct work_struct control_work;
+       struct work_struct config_work;
 
        struct list_head ports;
 
@@ -1837,10 +1838,21 @@ static void config_intr(struct virtio_device *vdev)
 
        portdev = vdev->priv;
 
+       if (!use_multiport(portdev))
+               schedule_work(&portdev->config_work);
+}
+
+static void config_work_handler(struct work_struct *work)
+{
+       struct ports_device *portdev;
+
+       portdev = container_of(work, struct ports_device, control_work);
        if (!use_multiport(portdev)) {
+               struct virtio_device *vdev;
                struct port *port;
                u16 rows, cols;
 
+               vdev = portdev->vdev;
                virtio_cread(vdev, struct virtio_console_config, cols, &cols);
                virtio_cread(vdev, struct virtio_console_config, rows, &rows);
 
@@ -2040,12 +2052,14 @@ static int virtcons_probe(struct virtio_device *vdev)
 
        virtio_device_ready(portdev->vdev);
 
+       INIT_WORK(&portdev->config_work, &config_work_handler);
+       INIT_WORK(&portdev->control_work, &control_work_handler);
+
        if (multiport) {
                unsigned int nr_added_bufs;
 
                spin_lock_init(&portdev->c_ivq_lock);
                spin_lock_init(&portdev->c_ovq_lock);
-               INIT_WORK(&portdev->control_work, &control_work_handler);
 
                nr_added_bufs = fill_queue(portdev->c_ivq,
                                           &portdev->c_ivq_lock);
@@ -2113,6 +2127,8 @@ static void virtcons_remove(struct virtio_device *vdev)
        /* Finish up work that's lined up */
        if (use_multiport(portdev))
                cancel_work_sync(&portdev->control_work);
+       else
+               cancel_work_sync(&portdev->config_work);
 
        list_for_each_entry_safe(port, port2, &portdev->ports, list)
                unplug_port(port);
@@ -2164,6 +2180,7 @@ static int virtcons_freeze(struct virtio_device *vdev)
 
        virtqueue_disable_cb(portdev->c_ivq);
        cancel_work_sync(&portdev->control_work);
+       cancel_work_sync(&portdev->config_work);
        /*
         * Once more: if control_work_handler() was running, it would
         * enable the cb as the last step.
index f07c8152e5cc42aa660f5c83c6c6470ee2e68502..3f27d21fb7297e70494bf35743f027f8c8005d73 100644 (file)
@@ -89,12 +89,29 @@ static int pmc_irq_set_type(struct irq_data *d, unsigned type)
        return 0;
 }
 
+static void pmc_irq_suspend(struct irq_data *d)
+{
+       struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
+
+       pmc->imr = pmc_read(pmc, AT91_PMC_IMR);
+       pmc_write(pmc, AT91_PMC_IDR, pmc->imr);
+}
+
+static void pmc_irq_resume(struct irq_data *d)
+{
+       struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
+
+       pmc_write(pmc, AT91_PMC_IER, pmc->imr);
+}
+
 static struct irq_chip pmc_irq = {
        .name = "PMC",
        .irq_disable = pmc_irq_mask,
        .irq_mask = pmc_irq_mask,
        .irq_unmask = pmc_irq_unmask,
        .irq_set_type = pmc_irq_set_type,
+       .irq_suspend = pmc_irq_suspend,
+       .irq_resume = pmc_irq_resume,
 };
 
 static struct lock_class_key pmc_lock_class;
@@ -224,7 +241,8 @@ static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
                goto out_free_pmc;
 
        pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
-       if (request_irq(pmc->virq, pmc_irq_handler, IRQF_SHARED, "pmc", pmc))
+       if (request_irq(pmc->virq, pmc_irq_handler,
+                       IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc))
                goto out_remove_irqdomain;
 
        return pmc;
index 52d2041fa3f6354a4abfdc8f45ee147a75a370ef..69abb08cf146513b0307a4a78449b2e5da971282 100644 (file)
@@ -33,6 +33,7 @@ struct at91_pmc {
        spinlock_t lock;
        const struct at91_pmc_caps *caps;
        struct irq_domain *irqdomain;
+       u32 imr;
 };
 
 static inline void pmc_lock(struct at91_pmc *pmc)
index db7f8bce7467a2abfd37f6ccb8e22c784a6bce28..25006a8bb8e6d5af8d145472fc76e2ef45281f09 100644 (file)
@@ -144,12 +144,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
                                   divider->flags);
 }
 
-/*
- * The reverse of DIV_ROUND_UP: The maximum number which
- * divided by m is r
- */
-#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
-
 static bool _is_valid_table_div(const struct clk_div_table *table,
                                                         unsigned int div)
 {
@@ -225,19 +219,24 @@ static int _div_round_closest(const struct clk_div_table *table,
                              unsigned long parent_rate, unsigned long rate,
                              unsigned long flags)
 {
-       int up, down, div;
+       int up, down;
+       unsigned long up_rate, down_rate;
 
-       up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       up = DIV_ROUND_UP(parent_rate, rate);
+       down = parent_rate / rate;
 
        if (flags & CLK_DIVIDER_POWER_OF_TWO) {
-               up = __roundup_pow_of_two(div);
-               down = __rounddown_pow_of_two(div);
+               up = __roundup_pow_of_two(up);
+               down = __rounddown_pow_of_two(down);
        } else if (table) {
-               up = _round_up_table(table, div);
-               down = _round_down_table(table, div);
+               up = _round_up_table(table, up);
+               down = _round_down_table(table, down);
        }
 
-       return (up - div) <= (div - down) ? up : down;
+       up_rate = DIV_ROUND_UP(parent_rate, up);
+       down_rate = DIV_ROUND_UP(parent_rate, down);
+
+       return (rate - up_rate) <= (down_rate - rate) ? up : down;
 }
 
 static int _div_round(const struct clk_div_table *table,
@@ -313,7 +312,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
                        return i;
                }
                parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
-                               MULT_ROUND_UP(rate, i));
+                                              rate * i);
                now = DIV_ROUND_UP(parent_rate, i);
                if (_is_best_div(rate, now, best, flags)) {
                        bestdiv = i;
@@ -353,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
                bestdiv = readl(divider->reg) >> divider->shift;
                bestdiv &= div_mask(divider->width);
                bestdiv = _get_div(divider->table, bestdiv, divider->flags);
-               return bestdiv;
+               return DIV_ROUND_UP(*prate, bestdiv);
        }
 
        return divider_round_rate(hw, rate, prate, divider->table,
index eb0152961d3c60652af108246e9d10be9d13a371..237f23f68bfce18cdfee3306487ba924906125c4 100644 (file)
@@ -1350,7 +1350,6 @@ static unsigned long clk_core_get_rate(struct clk_core *clk)
 
        return rate;
 }
-EXPORT_SYMBOL_GPL(clk_core_get_rate);
 
 /**
  * clk_get_rate - return the rate of clk
@@ -2170,6 +2169,32 @@ int clk_get_phase(struct clk *clk)
        return clk_core_get_phase(clk->core);
 }
 
+/**
+ * clk_is_match - check if two clk's point to the same hardware clock
+ * @p: clk compared against q
+ * @q: clk compared against p
+ *
+ * Returns true if the two struct clk pointers both point to the same hardware
+ * clock node. Put differently, returns true if struct clk *p and struct clk *q
+ * share the same struct clk_core object.
+ *
+ * Returns false otherwise. Note that two NULL clks are treated as matching.
+ */
+bool clk_is_match(const struct clk *p, const struct clk *q)
+{
+       /* trivial case: identical struct clk's or both NULL */
+       if (p == q)
+               return true;
+
+       /* true if clk->core pointers match. Avoid derefing garbage */
+       if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
+               if (p->core == q->core)
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(clk_is_match);
+
 /**
  * __clk_init - initialize the data structures in a struct clk
  * @dev:       device initializing this clk, placeholder for now
index b0b562b9ce0e0cc16949f588045b121cfc7d8046..e60feffc10a151dd77d291c71a81e8cb73234804 100644 (file)
@@ -48,6 +48,17 @@ static struct clk_pll pll3 = {
        },
 };
 
+static struct clk_regmap pll4_vote = {
+       .enable_reg = 0x34c0,
+       .enable_mask = BIT(4),
+       .hw.init = &(struct clk_init_data){
+               .name = "pll4_vote",
+               .parent_names = (const char *[]){ "pll4" },
+               .num_parents = 1,
+               .ops = &clk_pll_vote_ops,
+       },
+};
+
 static struct clk_pll pll8 = {
        .l_reg = 0x3144,
        .m_reg = 0x3148,
@@ -3023,6 +3034,7 @@ static struct clk_branch rpm_msg_ram_h_clk = {
 
 static struct clk_regmap *gcc_msm8960_clks[] = {
        [PLL3] = &pll3.clkr,
+       [PLL4_VOTE] = &pll4_vote,
        [PLL8] = &pll8.clkr,
        [PLL8_VOTE] = &pll8_vote,
        [PLL14] = &pll14.clkr,
@@ -3247,6 +3259,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
 
 static struct clk_regmap *gcc_apq8064_clks[] = {
        [PLL3] = &pll3.clkr,
+       [PLL4_VOTE] = &pll4_vote,
        [PLL8] = &pll8.clkr,
        [PLL8_VOTE] = &pll8_vote,
        [PLL14] = &pll14.clkr,
index 121ffde25dc3d6ec95d839699bc1f8829b0c003c..c9ff27b4648b56abc37499c1c8f284fc20da05d7 100644 (file)
@@ -462,7 +462,6 @@ static struct platform_driver lcc_ipq806x_driver = {
        .remove         = lcc_ipq806x_remove,
        .driver         = {
                .name   = "lcc-ipq806x",
-               .owner  = THIS_MODULE,
                .of_match_table = lcc_ipq806x_match_table,
        },
 };
index a75a408cfccddffe7e25486a4ca2c4e444c4e9c5..e2c863295f001fd5f99071dcf250ddd931967d09 100644 (file)
@@ -417,8 +417,8 @@ static struct clk_rcg slimbus_src = {
                .mnctr_en_bit = 8,
                .mnctr_reset_bit = 7,
                .mnctr_mode_shift = 5,
-               .n_val_shift = 16,
-               .m_val_shift = 16,
+               .n_val_shift = 24,
+               .m_val_shift = 8,
                .width = 8,
        },
        .p = {
@@ -547,7 +547,7 @@ static int lcc_msm8960_probe(struct platform_device *pdev)
                return PTR_ERR(regmap);
 
        /* Use the correct frequency plan depending on speed of PLL4 */
-       val = regmap_read(regmap, 0x4, &val);
+       regmap_read(regmap, 0x4, &val);
        if (val == 0x12) {
                slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
                mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
@@ -574,7 +574,6 @@ static struct platform_driver lcc_msm8960_driver = {
        .remove         = lcc_msm8960_remove,
        .driver         = {
                .name   = "lcc-msm8960",
-               .owner  = THIS_MODULE,
                .of_match_table = lcc_msm8960_match_table,
        },
 };
index 6ef89639a9f68bffd97990ee976cbd7b45826551..d21640634adf91e290537e28eb799aeea1042eed 100644 (file)
@@ -84,7 +84,7 @@ static int ti_fapll_enable(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       v |= (1 << FAPLL_MAIN_PLLEN);
+       v |= FAPLL_MAIN_PLLEN;
        writel_relaxed(v, fd->base);
 
        return 0;
@@ -95,7 +95,7 @@ static void ti_fapll_disable(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       v &= ~(1 << FAPLL_MAIN_PLLEN);
+       v &= ~FAPLL_MAIN_PLLEN;
        writel_relaxed(v, fd->base);
 }
 
@@ -104,7 +104,7 @@ static int ti_fapll_is_enabled(struct clk_hw *hw)
        struct fapll_data *fd = to_fapll(hw);
        u32 v = readl_relaxed(fd->base);
 
-       return v & (1 << FAPLL_MAIN_PLLEN);
+       return v & FAPLL_MAIN_PLLEN;
 }
 
 static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
index 1c2506f68122567df92d6197990ee1b015d0984f..a0b036ccb118b1fc23fa07907f17196c80a15a54 100644 (file)
@@ -63,6 +63,11 @@ config VT8500_TIMER
 config CADENCE_TTC_TIMER
        bool
 
+config ASM9260_TIMER
+       bool
+       select CLKSRC_MMIO
+       select CLKSRC_OF
+
 config CLKSRC_NOMADIK_MTU
        bool
        depends on (ARCH_NOMADIK || ARCH_U8500)
@@ -187,6 +192,7 @@ config SYS_SUPPORTS_EM_STI
 config SH_TIMER_CMT
        bool "Renesas CMT timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_CMT
        help
          This enables build of a clocksource and clockevent driver for
@@ -196,6 +202,7 @@ config SH_TIMER_CMT
 config SH_TIMER_MTU2
        bool "Renesas MTU2 timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_MTU2
        help
          This enables build of a clockevent driver for the Multi-Function
@@ -205,6 +212,7 @@ config SH_TIMER_MTU2
 config SH_TIMER_TMU
        bool "Renesas TMU timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_TMU
        help
          This enables build of a clocksource and clockevent driver for
@@ -245,15 +253,4 @@ config CLKSRC_PXA
        help
          This enables OST0 support available on PXA and SA-11x0
          platforms.
-
-config ASM9260_TIMER
-       bool "Alphascale ASM9260 timer driver"
-       depends on GENERIC_CLOCKEVENTS
-       select CLKSRC_MMIO
-       select CLKSRC_OF
-       default y if MACH_ASM9260
-       help
-         This enables build of a clocksource and clockevent driver for
-         the 32-bit System Timer hardware available on a Alphascale ASM9260.
-
 endmenu
index 32a3d25795d3a2b9303db120107d017c13c7165f..68ab42356d0e7a7cd4d97a453465633bba1c5e33 100644 (file)
@@ -224,6 +224,8 @@ static void __init mtk_timer_init(struct device_node *node)
        }
        rate = clk_get_rate(clk);
 
+       mtk_timer_global_reset(evt);
+
        if (request_irq(evt->dev.irq, mtk_timer_interrupt,
                        IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) {
                pr_warn("failed to setup irq %d\n", evt->dev.irq);
@@ -232,8 +234,6 @@ static void __init mtk_timer_init(struct device_node *node)
 
        evt->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
-       mtk_timer_global_reset(evt);
-
        /* Configure clock source */
        mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN);
        clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC),
@@ -241,10 +241,11 @@ static void __init mtk_timer_init(struct device_node *node)
 
        /* Configure clock event */
        mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT);
-       mtk_timer_enable_irq(evt, GPT_CLK_EVT);
-
        clockevents_config_and_register(&evt->dev, rate, 0x3,
                                        0xffffffff);
+
+       mtk_timer_enable_irq(evt, GPT_CLK_EVT);
+
        return;
 
 err_clk_disable:
index 941f3f344e08ab2ab552638f0e21ab41718a57ad..d9438af2bbd6b7d001bbdf524b7281a7a0c0816e 100644 (file)
@@ -163,7 +163,7 @@ static struct irqaction pxa_ost0_irq = {
        .dev_id         = &ckevt_pxa_osmr0,
 };
 
-static void pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
+static void __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
 {
        timer_writel(0, OIER);
        timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
index bba62f9deefbd0f71d59409daf85857cc2caa983..ec57ba2bbd87ac9f2a251e350598fa52019d7815 100644 (file)
@@ -225,12 +225,12 @@ static int __init efm32_clockevent_init(struct device_node *np)
        clock_event_ddata.base = base;
        clock_event_ddata.periodic_top = DIV_ROUND_CLOSEST(rate, 1024 * HZ);
 
-       setup_irq(irq, &efm32_clock_event_irq);
-
        clockevents_config_and_register(&clock_event_ddata.evtdev,
                                        DIV_ROUND_CLOSEST(rate, 1024),
                                        0xf, 0xffff);
 
+       setup_irq(irq, &efm32_clock_event_irq);
+
        return 0;
 
 err_get_irq:
index 02268448dc8540a9f53113f28c29e6a292209a5a..58597fbcc046f27f88238aa949730d6109a704b7 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/irq.h>
 #include <linux/irqreturn.h>
 #include <linux/reset.h>
-#include <linux/sched_clock.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -137,11 +136,6 @@ static struct irqaction sun5i_timer_irq = {
        .dev_id = &sun5i_clockevent,
 };
 
-static u64 sun5i_timer_sched_read(void)
-{
-       return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1));
-}
-
 static void __init sun5i_timer_init(struct device_node *node)
 {
        struct reset_control *rstc;
@@ -172,16 +166,11 @@ static void __init sun5i_timer_init(struct device_node *node)
        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
               timer_base + TIMER_CTL_REG(1));
 
-       sched_clock_register(sun5i_timer_sched_read, 32, rate);
        clocksource_mmio_init(timer_base + TIMER_CNTVAL_LO_REG(1), node->name,
                              rate, 340, 32, clocksource_mmio_readl_down);
 
        ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
-       ret = setup_irq(irq, &sun5i_timer_irq);
-       if (ret)
-               pr_warn("failed to setup irq %d\n", irq);
-
        /* Enable timer0 interrupt */
        val = readl(timer_base + TIMER_IRQ_EN_REG);
        writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
@@ -191,6 +180,10 @@ static void __init sun5i_timer_init(struct device_node *node)
 
        clockevents_config_and_register(&sun5i_clockevent, rate,
                                        TIMER_SYNC_TICKS, 0xffffffff);
+
+       ret = setup_irq(irq, &sun5i_timer_irq);
+       if (ret)
+               pr_warn("failed to setup irq %d\n", irq);
 }
 CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
                       sun5i_timer_init);
index 5e98c6b1f284b651f0b74d3673c55f997e47f081..82d2fbb20f7eb70d94a9c9c6e1d6ec3708f53ee0 100644 (file)
@@ -159,7 +159,7 @@ static struct cpufreq_driver exynos_driver = {
 
 static int exynos_cpufreq_probe(struct platform_device *pdev)
 {
-       struct device_node *cpus, *np;
+       struct device_node *cpu0;
        int ret = -EINVAL;
 
        exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
@@ -206,28 +206,19 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
        if (ret)
                goto err_cpufreq_reg;
 
-       cpus = of_find_node_by_path("/cpus");
-       if (!cpus) {
-               pr_err("failed to find cpus node\n");
+       cpu0 = of_get_cpu_node(0, NULL);
+       if (!cpu0) {
+               pr_err("failed to find cpu0 node\n");
                return 0;
        }
 
-       np = of_get_next_child(cpus, NULL);
-       if (!np) {
-               pr_err("failed to find cpus child node\n");
-               of_node_put(cpus);
-               return 0;
-       }
-
-       if (of_find_property(np, "#cooling-cells", NULL)) {
-               cdev = of_cpufreq_cooling_register(np,
+       if (of_find_property(cpu0, "#cooling-cells", NULL)) {
+               cdev = of_cpufreq_cooling_register(cpu0,
                                                   cpu_present_mask);
                if (IS_ERR(cdev))
                        pr_err("running cpufreq without cooling device: %ld\n",
                               PTR_ERR(cdev));
        }
-       of_node_put(np);
-       of_node_put(cpus);
 
        return 0;
 
index bee5df7794d33d1078116c8ac2f3618075230c8c..7cb4b766cf948d3f3e4b813325eda0aa0f0129aa 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/smp.h>
 #include <sysdev/fsl_soc.h>
 
+#include <asm/smp.h>   /* for get_hard_smp_processor_id() in UP configs */
+
 /**
  * struct cpu_data - per CPU data struct
  * @parent: the parent node of cpu clock
index 38e68618513a4728fe637a46b6a6ce79edb54730..980151f34707b2560aab8b1dbe84457b07308949 100644 (file)
@@ -37,11 +37,11 @@ static int mvebu_v7_enter_idle(struct cpuidle_device *dev,
                deepidle = true;
 
        ret = mvebu_v7_cpu_suspend(deepidle);
+       cpu_pm_exit();
+
        if (ret)
                return ret;
 
-       cpu_pm_exit();
-
        return index;
 }
 
@@ -50,17 +50,17 @@ static struct cpuidle_driver armadaxp_idle_driver = {
        .states[0]              = ARM_CPUIDLE_WFI_STATE,
        .states[1]              = {
                .enter                  = mvebu_v7_enter_idle,
-               .exit_latency           = 10,
+               .exit_latency           = 100,
                .power_usage            = 50,
-               .target_residency       = 100,
+               .target_residency       = 1000,
                .name                   = "MV CPU IDLE",
                .desc                   = "CPU power down",
        },
        .states[2]              = {
                .enter                  = mvebu_v7_enter_idle,
-               .exit_latency           = 100,
+               .exit_latency           = 1000,
                .power_usage            = 5,
-               .target_residency       = 1000,
+               .target_residency       = 10000,
                .flags                  = MVEBU_V7_FLAG_DEEP_IDLE,
                .name                   = "MV CPU DEEP IDLE",
                .desc                   = "CPU and L2 Fabric power down",
index 4d534582514e014b5fdb3fc5e0b9db7e52c7b306..080bd2dbde4ba5408504a451e9454b51497202e3 100644 (file)
@@ -44,6 +44,12 @@ void disable_cpuidle(void)
        off = 1;
 }
 
+bool cpuidle_not_available(struct cpuidle_driver *drv,
+                          struct cpuidle_device *dev)
+{
+       return off || !initialized || !drv || !dev || !dev->enabled;
+}
+
 /**
  * cpuidle_play_dead - cpu off-lining
  *
@@ -66,14 +72,8 @@ int cpuidle_play_dead(void)
        return -ENODEV;
 }
 
-/**
- * cpuidle_find_deepest_state - Find deepest state meeting specific conditions.
- * @drv: cpuidle driver for the given CPU.
- * @dev: cpuidle device for the given CPU.
- * @freeze: Whether or not the state should be suitable for suspend-to-idle.
- */
-static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
-                                     struct cpuidle_device *dev, bool freeze)
+static int find_deepest_state(struct cpuidle_driver *drv,
+                             struct cpuidle_device *dev, bool freeze)
 {
        unsigned int latency_req = 0;
        int i, ret = freeze ? -1 : CPUIDLE_DRIVER_STATE_START - 1;
@@ -92,6 +92,17 @@ static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
        return ret;
 }
 
+/**
+ * cpuidle_find_deepest_state - Find the deepest available idle state.
+ * @drv: cpuidle driver for the given CPU.
+ * @dev: cpuidle device for the given CPU.
+ */
+int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                              struct cpuidle_device *dev)
+{
+       return find_deepest_state(drv, dev, false);
+}
+
 static void enter_freeze_proper(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev, int index)
 {
@@ -113,15 +124,14 @@ static void enter_freeze_proper(struct cpuidle_driver *drv,
 
 /**
  * cpuidle_enter_freeze - Enter an idle state suitable for suspend-to-idle.
+ * @drv: cpuidle driver for the given CPU.
+ * @dev: cpuidle device for the given CPU.
  *
  * If there are states with the ->enter_freeze callback, find the deepest of
- * them and enter it with frozen tick.  Otherwise, find the deepest state
- * available and enter it normally.
+ * them and enter it with frozen tick.
  */
-void cpuidle_enter_freeze(void)
+int cpuidle_enter_freeze(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
-       struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
-       struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int index;
 
        /*
@@ -129,24 +139,11 @@ void cpuidle_enter_freeze(void)
         * that interrupts won't be enabled when it exits and allows the tick to
         * be frozen safely.
         */
-       index = cpuidle_find_deepest_state(drv, dev, true);
-       if (index >= 0) {
-               enter_freeze_proper(drv, dev, index);
-               return;
-       }
-
-       /*
-        * It is not safe to freeze the tick, find the deepest state available
-        * at all and try to enter it normally.
-        */
-       index = cpuidle_find_deepest_state(drv, dev, false);
+       index = find_deepest_state(drv, dev, true);
        if (index >= 0)
-               cpuidle_enter(drv, dev, index);
-       else
-               arch_cpu_idle();
+               enter_freeze_proper(drv, dev, index);
 
-       /* Interrupts are enabled again here. */
-       local_irq_disable();
+       return index;
 }
 
 /**
@@ -205,12 +202,6 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
  */
 int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
-       if (off || !initialized)
-               return -ENODEV;
-
-       if (!drv || !dev || !dev->enabled)
-               return -EBUSY;
-
        return cpuidle_curr_governor->select(drv, dev);
 }
 
index e5541117b3e915de7f08ecc38a58ec9f72bf2c12..50ef8bd8708ba69d93808510c9a8be473d377d7c 100644 (file)
@@ -159,6 +159,9 @@ fence_wait_timeout(struct fence *fence, bool intr, signed long timeout)
        if (WARN_ON(timeout < 0))
                return -EINVAL;
 
+       if (timeout == 0)
+               return fence_is_signaled(fence);
+
        trace_fence_wait_start(fence);
        ret = fence->ops->wait(fence, intr, timeout);
        trace_fence_wait_end(fence);
index 3c97c8fa8d02687290e7340f82666f3466fbda2e..39920d77f288d7802c054130acf72caa8f40465d 100644 (file)
@@ -327,6 +327,9 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
        unsigned seq, shared_count, i = 0;
        long ret = timeout;
 
+       if (!timeout)
+               return reservation_object_test_signaled_rcu(obj, wait_all);
+
 retry:
        fence = NULL;
        shared_count = 0;
@@ -402,8 +405,6 @@ reservation_object_test_signaled_single(struct fence *passed_fence)
        int ret = 1;
 
        if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
-               int ret;
-
                fence = fence_get_rcu(lfence);
                if (!fence)
                        return -1;
index 4a5fd245014e6666721c111b85515b2e1b05f74c..83aa55d6fa5d65e6243abc13e29c1d4766768eeb 100644 (file)
 
 #define DRIVER_NAME    "pl08xdmac"
 
+#define PL80X_DMA_BUSWIDTHS \
+       BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
+       BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)
+
 static struct amba_driver pl08x_amba_driver;
 struct pl08x_driver_data;
 
@@ -2070,6 +2076,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->memcpy.device_pause = pl08x_pause;
        pl08x->memcpy.device_resume = pl08x_resume;
        pl08x->memcpy.device_terminate_all = pl08x_terminate_all;
+       pl08x->memcpy.src_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->memcpy.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->memcpy.directions = BIT(DMA_MEM_TO_MEM);
+       pl08x->memcpy.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
        /* Initialize slave engine */
        dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
@@ -2086,6 +2096,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->slave.device_pause = pl08x_pause;
        pl08x->slave.device_resume = pl08x_resume;
        pl08x->slave.device_terminate_all = pl08x_terminate_all;
+       pl08x->slave.src_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->slave.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
+       pl08x->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       pl08x->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
        /* Get the platform data */
        pl08x->pd = dev_get_platdata(&adev->dev);
index 1e1a4c5675426048dcef03616c15d8e744db2c6e..0b4fc6fb48ce7c5cec62d9a1ef4291e0b175cfaf 100644 (file)
@@ -238,93 +238,126 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
 }
 
 /*
- * atc_get_current_descriptors -
- * locate the descriptor which equal to physical address in DSCR
- * @atchan: the channel we want to start
- * @dscr_addr: physical descriptor address in DSCR
+ * atc_get_desc_by_cookie - get the descriptor of a cookie
+ * @atchan: the DMA channel
+ * @cookie: the cookie to get the descriptor for
  */
-static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
-                                                       u32 dscr_addr)
+static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
+                                               dma_cookie_t cookie)
 {
-       struct at_desc  *desc, *_desc, *child, *desc_cur = NULL;
+       struct at_desc *desc, *_desc;
 
-       list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
-               if (desc->lli.dscr == dscr_addr) {
-                       desc_cur = desc;
-                       break;
-               }
+       list_for_each_entry_safe(desc, _desc, &atchan->queue, desc_node) {
+               if (desc->txd.cookie == cookie)
+                       return desc;
+       }
 
-               list_for_each_entry(child, &desc->tx_list, desc_node) {
-                       if (child->lli.dscr == dscr_addr) {
-                               desc_cur = child;
-                               break;
-                       }
-               }
+       list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
+               if (desc->txd.cookie == cookie)
+                       return desc;
        }
 
-       return desc_cur;
+       return NULL;
 }
 
-/*
- * atc_get_bytes_left -
- * Get the number of bytes residue in dma buffer,
- * @chan: the channel we want to start
+/**
+ * atc_calc_bytes_left - calculates the number of bytes left according to the
+ * value read from CTRLA.
+ *
+ * @current_len: the number of bytes left before reading CTRLA
+ * @ctrla: the value of CTRLA
+ * @desc: the descriptor containing the transfer width
+ */
+static inline int atc_calc_bytes_left(int current_len, u32 ctrla,
+                                       struct at_desc *desc)
+{
+       return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
+}
+
+/**
+ * atc_calc_bytes_left_from_reg - calculates the number of bytes left according
+ * to the current value of CTRLA.
+ *
+ * @current_len: the number of bytes left before reading CTRLA
+ * @atchan: the channel to read CTRLA for
+ * @desc: the descriptor containing the transfer width
+ */
+static inline int atc_calc_bytes_left_from_reg(int current_len,
+                       struct at_dma_chan *atchan, struct at_desc *desc)
+{
+       u32 ctrla = channel_readl(atchan, CTRLA);
+
+       return atc_calc_bytes_left(current_len, ctrla, desc);
+}
+
+/**
+ * atc_get_bytes_left - get the number of bytes residue for a cookie
+ * @chan: DMA channel
+ * @cookie: transaction identifier to check status of
  */
-static int atc_get_bytes_left(struct dma_chan *chan)
+static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
-       struct at_dma           *atdma = to_at_dma(chan->device);
-       int     chan_id = atchan->chan_common.chan_id;
        struct at_desc *desc_first = atc_first_active(atchan);
-       struct at_desc *desc_cur;
-       int ret = 0, count = 0;
+       struct at_desc *desc;
+       int ret;
+       u32 ctrla, dscr;
 
        /*
-        * Initialize necessary values in the first time.
-        * remain_desc record remain desc length.
+        * If the cookie doesn't match to the currently running transfer then
+        * we can return the total length of the associated DMA transfer,
+        * because it is still queued.
         */
-       if (atchan->remain_desc == 0)
-               /* First descriptor embedds the transaction length */
-               atchan->remain_desc = desc_first->len;
+       desc = atc_get_desc_by_cookie(atchan, cookie);
+       if (desc == NULL)
+               return -EINVAL;
+       else if (desc != desc_first)
+               return desc->total_len;
 
-       /*
-        * This happens when current descriptor transfer complete.
-        * The residual buffer size should reduce current descriptor length.
-        */
-       if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
-               clear_bit(ATC_IS_BTC, &atchan->status);
-               desc_cur = atc_get_current_descriptors(atchan,
-                                               channel_readl(atchan, DSCR));
-               if (!desc_cur) {
-                       ret = -EINVAL;
-                       goto out;
-               }
+       /* cookie matches to the currently running transfer */
+       ret = desc_first->total_len;
 
-               count = (desc_cur->lli.ctrla & ATC_BTSIZE_MAX)
-                       << desc_first->tx_width;
-               if (atchan->remain_desc < count) {
-                       ret = -EINVAL;
-                       goto out;
+       if (desc_first->lli.dscr) {
+               /* hardware linked list transfer */
+
+               /*
+                * Calculate the residue by removing the length of the child
+                * descriptors already transferred from the total length.
+                * To get the current child descriptor we can use the value of
+                * the channel's DSCR register and compare it against the value
+                * of the hardware linked list structure of each child
+                * descriptor.
+                */
+
+               ctrla = channel_readl(atchan, CTRLA);
+               rmb(); /* ensure CTRLA is read before DSCR */
+               dscr = channel_readl(atchan, DSCR);
+
+               /* for the first descriptor we can be more accurate */
+               if (desc_first->lli.dscr == dscr)
+                       return atc_calc_bytes_left(ret, ctrla, desc_first);
+
+               ret -= desc_first->len;
+               list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
+                       if (desc->lli.dscr == dscr)
+                               break;
+
+                       ret -= desc->len;
                }
 
-               atchan->remain_desc -= count;
-               ret = atchan->remain_desc;
-       } else {
                /*
-                * Get residual bytes when current
-                * descriptor transfer in progress.
+                * For the last descriptor in the chain we can calculate
+                * the remaining bytes using the channel's register.
+                * Note that the transfer width of the first and last
+                * descriptor may differ.
                 */
-               count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX)
-                               << (desc_first->tx_width);
-               ret = atchan->remain_desc - count;
+               if (!desc->lli.dscr)
+                       ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
+       } else {
+               /* single transfer */
+               ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
        }
-       /*
-        * Check fifo empty.
-        */
-       if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id)))
-               atc_issue_pending(chan);
 
-out:
        return ret;
 }
 
@@ -539,8 +572,6 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
                                        /* Give information to tasklet */
                                        set_bit(ATC_IS_ERROR, &atchan->status);
                                }
-                               if (pending & AT_DMA_BTC(i))
-                                       set_bit(ATC_IS_BTC, &atchan->status);
                                tasklet_schedule(&atchan->tasklet);
                                ret = IRQ_HANDLED;
                        }
@@ -653,14 +684,18 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                desc->lli.ctrlb = ctrlb;
 
                desc->txd.cookie = 0;
+               desc->len = xfer_count << src_width;
 
                atc_desc_chain(&first, &prev, desc);
        }
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = len;
+       first->total_len = len;
+
+       /* set transfer width for the calculation of the residue */
        first->tx_width = src_width;
+       prev->tx_width = src_width;
 
        /* set end-of-link to the last link descriptor of list*/
        set_desc_eol(desc);
@@ -752,6 +787,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | ATC_SRC_WIDTH(mem_width)
                                        | len >> mem_width;
                        desc->lli.ctrlb = ctrlb;
+                       desc->len = len;
 
                        atc_desc_chain(&first, &prev, desc);
                        total_len += len;
@@ -792,6 +828,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                                        | ATC_DST_WIDTH(mem_width)
                                        | len >> reg_width;
                        desc->lli.ctrlb = ctrlb;
+                       desc->len = len;
 
                        atc_desc_chain(&first, &prev, desc);
                        total_len += len;
@@ -806,8 +843,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = total_len;
+       first->total_len = total_len;
+
+       /* set transfer width for the calculation of the residue */
        first->tx_width = reg_width;
+       prev->tx_width = reg_width;
 
        /* first link descriptor of list is responsible of flags */
        first->txd.flags = flags; /* client is in control of this ack */
@@ -872,6 +912,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
                                | ATC_FC_MEM2PER
                                | ATC_SIF(atchan->mem_if)
                                | ATC_DIF(atchan->per_if);
+               desc->len = period_len;
                break;
 
        case DMA_DEV_TO_MEM:
@@ -883,6 +924,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
                                | ATC_FC_PER2MEM
                                | ATC_SIF(atchan->per_if)
                                | ATC_DIF(atchan->mem_if);
+               desc->len = period_len;
                break;
 
        default:
@@ -964,7 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
-       first->len = buf_len;
+       first->total_len = buf_len;
        first->tx_width = reg_width;
 
        return &first->txd;
@@ -1118,7 +1160,7 @@ atc_tx_status(struct dma_chan *chan,
        spin_lock_irqsave(&atchan->lock, flags);
 
        /*  Get number of bytes left in the active transactions */
-       bytes = atc_get_bytes_left(chan);
+       bytes = atc_get_bytes_left(chan, cookie);
 
        spin_unlock_irqrestore(&atchan->lock, flags);
 
@@ -1214,7 +1256,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 
        spin_lock_irqsave(&atchan->lock, flags);
        atchan->descs_allocated = i;
-       atchan->remain_desc = 0;
        list_splice(&tmp_list, &atchan->free_list);
        dma_cookie_init(chan);
        spin_unlock_irqrestore(&atchan->lock, flags);
@@ -1257,7 +1298,6 @@ static void atc_free_chan_resources(struct dma_chan *chan)
        list_splice_init(&atchan->free_list, &list);
        atchan->descs_allocated = 0;
        atchan->status = 0;
-       atchan->remain_desc = 0;
 
        dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
 }
index d6bba6c636c2b9ab4f05331084e07f59b797f1aa..2727ca560572586482cb53a0f38522e0b66abfe3 100644 (file)
@@ -181,8 +181,9 @@ struct at_lli {
  * @at_lli: hardware lli structure
  * @txd: support for the async_tx api
  * @desc_node: node on the channed descriptors list
- * @len: total transaction bytecount
+ * @len: descriptor byte count
  * @tx_width: transfer width
+ * @total_len: total transaction byte count
  */
 struct at_desc {
        /* FIRST values the hardware uses */
@@ -194,6 +195,7 @@ struct at_desc {
        struct list_head                desc_node;
        size_t                          len;
        u32                             tx_width;
+       size_t                          total_len;
 };
 
 static inline struct at_desc *
@@ -213,7 +215,6 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
 enum atc_status {
        ATC_IS_ERROR = 0,
        ATC_IS_PAUSED = 1,
-       ATC_IS_BTC = 2,
        ATC_IS_CYCLIC = 24,
 };
 
@@ -231,7 +232,6 @@ enum atc_status {
  * @save_cfg: configuration register that is saved on suspend/resume cycle
  * @save_dscr: for cyclic operations, preserve next descriptor address in
  *             the cyclic list on suspend/resume cycle
- * @remain_desc: to save remain desc length
  * @dma_sconfig: configuration for slave transfers, passed via
  * .device_config
  * @lock: serializes enqueue/dequeue operations to descriptors lists
@@ -251,7 +251,6 @@ struct at_dma_chan {
        struct tasklet_struct   tasklet;
        u32                     save_cfg;
        u32                     save_dscr;
-       u32                     remain_desc;
        struct dma_slave_config dma_sconfig;
 
        spinlock_t              lock;
index 09e2825a547a2098cc28a0e3e20079c33c52fe09..d9891d3461f6fbd42f5cb85041147513ca07ba73 100644 (file)
@@ -664,7 +664,6 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
        struct at_xdmac_desc    *first = NULL, *prev = NULL;
        unsigned int            periods = buf_len / period_len;
        int                     i;
-       u32                     cfg;
 
        dev_dbg(chan2dev(chan), "%s: buf_addr=%pad, buf_len=%zd, period_len=%zd, dir=%s, flags=0x%lx\n",
                __func__, &buf_addr, buf_len, period_len,
@@ -700,17 +699,17 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
                if (direction == DMA_DEV_TO_MEM) {
                        desc->lld.mbr_sa = atchan->per_src_addr;
                        desc->lld.mbr_da = buf_addr + i * period_len;
-                       cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
+                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
                } else {
                        desc->lld.mbr_sa = buf_addr + i * period_len;
                        desc->lld.mbr_da = atchan->per_dst_addr;
-                       cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
+                       desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
                }
                desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1
                        | AT_XDMAC_MBR_UBC_NDEN
                        | AT_XDMAC_MBR_UBC_NSEN
                        | AT_XDMAC_MBR_UBC_NDE
-                       | period_len >> at_xdmac_get_dwidth(cfg);
+                       | period_len >> at_xdmac_get_dwidth(desc->lld.mbr_cfg);
 
                dev_dbg(chan2dev(chan),
                         "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
index 0723096fb50ac125dbb471126ba396085307ff2e..c92d6a70ccf303c69cfdb127210a09a1262122bc 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 4527a3ebeac446f58a4c3b3b8722d6caf16b1b63..84884418fd30fc73a700bde9c0bebd67d72ea0a5 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 455b7a4f1e87fe890019eb6acd459e8d7c000667..a8ad05291b274498b55deef4bba88a2dbf1ffbd3 100644 (file)
@@ -626,7 +626,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
        dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status);
 
        /* Check if we have any interrupt from the DMAC */
-       if (!status)
+       if (!status || !dw->in_use)
                return IRQ_NONE;
 
        /*
index 6565a361e7e51c7e80bbbc6d920880b47aa71af8..b2c3ae07142910a39c90b7ed47f718af35821021 100644 (file)
@@ -26,6 +26,8 @@
 
 #include "internal.h"
 
+#define DRV_NAME       "dw_dmac"
+
 static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
                                        struct of_dma *ofdma)
 {
@@ -284,7 +286,7 @@ static struct platform_driver dw_driver = {
        .remove         = dw_remove,
        .shutdown       = dw_shutdown,
        .driver = {
-               .name   = "dw_dmac",
+               .name   = DRV_NAME,
                .pm     = &dw_dev_pm_ops,
                .of_match_table = of_match_ptr(dw_dma_of_id_table),
                .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
@@ -305,3 +307,4 @@ module_exit(dw_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
+MODULE_ALIAS("platform:" DRV_NAME);
index 276157f22612dc18140b84294ab1ef49ecf46ebc..53dbd3b3384cfd8b00940f7a7cd752b28bcac71a 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 18c0a131e4e41d21ec9ffab272f26258fb483011..66a0efb9651d3d8f3240701fafe2299b9abca598 100644 (file)
@@ -531,6 +531,10 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
                dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
        }
 
+       /* Set bits of CONFIG register with dynamic context switching */
+       if (readl(sdma->regs + SDMA_H_CONFIG) == 0)
+               writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+
        return ret ? 0 : -ETIMEDOUT;
 }
 
@@ -1394,9 +1398,6 @@ static int sdma_init(struct sdma_engine *sdma)
 
        writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
 
-       /* Set bits of CONFIG register with given context switching mode */
-       writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
-
        /* Initializes channel's priorities */
        sdma_set_channel_priority(&sdma->channel[0], 7);
 
index 77a6dcf25b98b818b9d83ecbbf0d99edc3783056..194ec20c940841c9b0de473ac43417f4235c0482 100644 (file)
@@ -230,6 +230,10 @@ static bool is_bwd_noraid(struct pci_dev *pdev)
        switch (pdev->device) {
        case PCI_DEVICE_ID_INTEL_IOAT_BWD2:
        case PCI_DEVICE_ID_INTEL_IOAT_BWD3:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE0:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE1:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE2:
+       case PCI_DEVICE_ID_INTEL_IOAT_BDXDE3:
                return true;
        default:
                return false;
index 8926f271904e45dcf1f4ed7532afe6fc3cbdb323..eb410044e1af5415f4aa1aad48f7564588be1bb1 100644 (file)
@@ -219,6 +219,9 @@ static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id)
 
        while (dint) {
                i = __ffs(dint);
+               /* only handle interrupts belonging to pdma driver*/
+               if (i >= pdev->dma_channels)
+                       break;
                dint &= (dint - 1);
                phy = &pdev->phy[i];
                ret = mmp_pdma_chan_handler(irq, phy);
@@ -999,6 +1002,9 @@ static int mmp_pdma_probe(struct platform_device *op)
        struct resource *iores;
        int i, ret, irq = 0;
        int dma_channels = 0, irq_num = 0;
+       const enum dma_slave_buswidth widths =
+               DMA_SLAVE_BUSWIDTH_1_BYTE   | DMA_SLAVE_BUSWIDTH_2_BYTES |
+               DMA_SLAVE_BUSWIDTH_4_BYTES;
 
        pdev = devm_kzalloc(&op->dev, sizeof(*pdev), GFP_KERNEL);
        if (!pdev)
@@ -1066,6 +1072,10 @@ static int mmp_pdma_probe(struct platform_device *op)
        pdev->device.device_config = mmp_pdma_config;
        pdev->device.device_terminate_all = mmp_pdma_terminate_all;
        pdev->device.copy_align = PDMA_ALIGNMENT;
+       pdev->device.src_addr_widths = widths;
+       pdev->device.dst_addr_widths = widths;
+       pdev->device.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+       pdev->device.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
 
        if (pdev->dev->coherent_dma_mask)
                dma_set_mask(pdev->dev, pdev->dev->coherent_dma_mask);
index 70c2fa9963cd4d942afa0b8a99f42c4d2ede784b..b6f4e1fc9c784cc0a3fce3d76877774760cd8c59 100644 (file)
@@ -110,7 +110,7 @@ struct mmp_tdma_chan {
        struct tasklet_struct           tasklet;
 
        struct mmp_tdma_desc            *desc_arr;
-       phys_addr_t                     desc_arr_phys;
+       dma_addr_t                      desc_arr_phys;
        int                             desc_num;
        enum dma_transfer_direction     dir;
        dma_addr_t                      dev_addr;
@@ -166,9 +166,12 @@ static void mmp_tdma_enable_chan(struct mmp_tdma_chan *tdmac)
 static int mmp_tdma_disable_chan(struct dma_chan *chan)
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+       u32 tdcr;
 
-       writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
-                                       tdmac->reg_base + TDCR);
+       tdcr = readl(tdmac->reg_base + TDCR);
+       tdcr |= TDCR_ABR;
+       tdcr &= ~TDCR_CHANEN;
+       writel(tdcr, tdmac->reg_base + TDCR);
 
        tdmac->status = DMA_COMPLETE;
 
@@ -296,12 +299,27 @@ static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
        return -EAGAIN;
 }
 
+static size_t mmp_tdma_get_pos(struct mmp_tdma_chan *tdmac)
+{
+       size_t reg;
+
+       if (tdmac->idx == 0) {
+               reg = __raw_readl(tdmac->reg_base + TDSAR);
+               reg -= tdmac->desc_arr[0].src_addr;
+       } else if (tdmac->idx == 1) {
+               reg = __raw_readl(tdmac->reg_base + TDDAR);
+               reg -= tdmac->desc_arr[0].dst_addr;
+       } else
+               return -EINVAL;
+
+       return reg;
+}
+
 static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
 {
        struct mmp_tdma_chan *tdmac = dev_id;
 
        if (mmp_tdma_clear_chan_irq(tdmac) == 0) {
-               tdmac->pos = (tdmac->pos + tdmac->period_len) % tdmac->buf_len;
                tasklet_schedule(&tdmac->tasklet);
                return IRQ_HANDLED;
        } else
@@ -343,7 +361,7 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
        int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
 
        gpool = tdmac->pool;
-       if (tdmac->desc_arr)
+       if (gpool && tdmac->desc_arr)
                gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
                                size);
        tdmac->desc_arr = NULL;
@@ -499,6 +517,7 @@ static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
 
+       tdmac->pos = mmp_tdma_get_pos(tdmac);
        dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
                         tdmac->buf_len - tdmac->pos);
 
@@ -610,7 +629,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
        int i, ret;
        int irq = 0, irq_num = 0;
        int chan_num = TDMA_CHANNEL_NUM;
-       struct gen_pool *pool;
+       struct gen_pool *pool = NULL;
 
        of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
        if (of_id)
index 15cab7d79525914d862e5cd38344bc2e3046c95a..b4634109e0100905dd39d285f03d669c405cbef0 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 ca31f1b45366d232339cbf0ed17d5ee0ee9e0ca5..cbd4a8aff120879a7f210329c1bc780a034c5287 100644 (file)
@@ -194,6 +194,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
 
        return ERR_PTR(ret_no_channel);
 }
+EXPORT_SYMBOL_GPL(of_dma_request_slave_channel);
 
 /**
  * of_dma_simple_xlate - Simple DMA engine translation function
index 7dd6dd1216819543aae06f2d3dd2707d16917c24..167dbaf6574275a0fffd5590b7a169e811320b39 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 d7a33b3ac46603883e61577f80e29076c0b71221..9c914d62590626fb8f407d7f0bed63b27c37a4f1 100644 (file)
@@ -162,9 +162,9 @@ static const struct reg_offset_data bam_v1_4_reg_info[] = {
        [BAM_P_IRQ_STTS]        = { 0x1010, 0x1000, 0x00, 0x00 },
        [BAM_P_IRQ_CLR]         = { 0x1014, 0x1000, 0x00, 0x00 },
        [BAM_P_IRQ_EN]          = { 0x1018, 0x1000, 0x00, 0x00 },
-       [BAM_P_EVNT_DEST_ADDR]  = { 0x102C, 0x00, 0x1000, 0x00 },
-       [BAM_P_EVNT_REG]        = { 0x1018, 0x00, 0x1000, 0x00 },
-       [BAM_P_SW_OFSTS]        = { 0x1000, 0x00, 0x1000, 0x00 },
+       [BAM_P_EVNT_DEST_ADDR]  = { 0x182C, 0x00, 0x1000, 0x00 },
+       [BAM_P_EVNT_REG]        = { 0x1818, 0x00, 0x1000, 0x00 },
+       [BAM_P_SW_OFSTS]        = { 0x1800, 0x00, 0x1000, 0x00 },
        [BAM_P_DATA_FIFO_ADDR]  = { 0x1824, 0x00, 0x1000, 0x00 },
        [BAM_P_DESC_FIFO_ADDR]  = { 0x181C, 0x00, 0x1000, 0x00 },
        [BAM_P_EVNT_GEN_TRSHLD] = { 0x1828, 0x00, 0x1000, 0x00 },
@@ -1143,6 +1143,10 @@ static int bam_dma_probe(struct platform_device *pdev)
        dma_cap_set(DMA_SLAVE, bdev->common.cap_mask);
 
        /* initialize dmaengine apis */
+       bdev->common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       bdev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+       bdev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       bdev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
        bdev->common.device_alloc_chan_resources = bam_alloc_chan;
        bdev->common.device_free_chan_resources = bam_free_chan;
        bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
index b2431aa300331270fa949ea5c14c41602a6c8e69..9f1d4c7dbab8389039e4ae1da636ca13521314ee 100644 (file)
@@ -582,15 +582,12 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
        }
 }
 
-static void sh_dmae_shutdown(struct platform_device *pdev)
-{
-       struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
-       sh_dmae_ctl_stop(shdev);
-}
-
 #ifdef CONFIG_PM
 static int sh_dmae_runtime_suspend(struct device *dev)
 {
+       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+       sh_dmae_ctl_stop(shdev);
        return 0;
 }
 
@@ -605,6 +602,9 @@ static int sh_dmae_runtime_resume(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int sh_dmae_suspend(struct device *dev)
 {
+       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+       sh_dmae_ctl_stop(shdev);
        return 0;
 }
 
@@ -929,13 +929,12 @@ static int sh_dmae_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver sh_dmae_driver = {
-       .driver         = {
+       .driver         = {
                .pm     = &sh_dmae_pm,
                .name   = SH_DMAE_DRV_NAME,
                .of_match_table = sh_dmae_of_match,
        },
        .remove         = sh_dmae_remove,
-       .shutdown       = sh_dmae_shutdown,
 };
 
 static int __init sh_dmae_init(void)
index c5f7b4e9eb6c6e490454958473893820bccaeb10..2eebd28b4c40af2789c32e0008f2b60006fc03ac 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 2fe195002021d079ec36515a7ebba4385c1f3600..f07d4a67fa76b3a3cb542e31a24a093c6f7aff97 100644 (file)
@@ -179,12 +179,12 @@ again:
                start = desc->phys_addr;
                end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
 
-               if ((start + size) > end || (start + size) > max)
-                       continue;
-
-               if (end - size > max)
+               if (end > max)
                        end = max;
 
+               if ((start + size) > end)
+                       continue;
+
                if (round_down(end - size, align) < start)
                        continue;
 
index a6952ba343a89747b919b45aa4d9e07951762fcd..a65b75161aa49d16749258407db18c7cfc30f79f 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 257e2989215c035b87fbef2f7b086c58b722e266..045a952576c708e253de29438abaec95640989f2 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 472fb5b8779f3723f969998b54716b3081901649..9cdbc0c9cb2da87abc65dda442fc75a1612cc51e 100644 (file)
@@ -26,9 +26,12 @@ struct tps65912_gpio_data {
        struct gpio_chip gpio_chip;
 };
 
+#define to_tgd(gc) container_of(gc, struct tps65912_gpio_data, gpio_chip)
+
 static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
        int val;
 
        val = tps65912_reg_read(tps65912, TPS65912_GPIO1 + offset);
@@ -42,7 +45,8 @@ static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
 static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
                              int value)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        if (value)
                tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
@@ -55,7 +59,8 @@ static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
 static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
                                int value)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        /* Set the initial value */
        tps65912_gpio_set(gc, offset, value);
@@ -66,7 +71,8 @@ static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
 
 static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset)
 {
-       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+       struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
        return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
                                                                GPIO_CFG_MASK);
index c0929d938ced866e343e0230e00fc5c9cda77c0b..df990f29757a7e045fd8a42760944b2d8bd2ba84 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 8cad8e400b44d674ad144e817daa7b63139f2041..4650bf830d6b6306f96e309d4f2782da8a859575 100644 (file)
@@ -46,12 +46,13 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
 
        ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
        if (ret < 0) {
-               /* We've found the gpio chip, but the translation failed.
-                * Return true to stop looking and return the translation
-                * error via out_gpio
+               /* We've found a gpio chip, but the translation failed.
+                * Store translation error in out_gpio.
+                * Return false to keep looking, as more than one gpio chip
+                * could be registered per of-node.
                 */
                gg_data->out_gpio = ERR_PTR(ret);
-               return true;
+               return false;
         }
 
        gg_data->out_gpio = gpiochip_get_desc(gc, ret);
index b3589d0e39b9c2027a4e680625663dfdcbe3cc63..d8135adb2238012460cfb67165d0f322f809230a 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 d64f86cda34f5a155e176526d5f3a3463b96c826..488f51d19427a8273b672df18962a4dafe9feaf5 100644 (file)
@@ -163,6 +163,8 @@ void program_sh_mem_settings(struct device_queue_manager *dqm,
                                        struct qcm_process_device *qpd);
 int init_pipelines(struct device_queue_manager *dqm,
                unsigned int pipes_num, unsigned int first_pipe);
+unsigned int get_first_pipe(struct device_queue_manager *dqm);
+unsigned int get_pipes_num(struct device_queue_manager *dqm);
 
 extern inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
 {
@@ -175,10 +177,4 @@ get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
        return (pdd->lds_base >> 60) & 0x0E;
 }
 
-extern inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
-{
-       BUG_ON(!dqm || !dqm->dev);
-       return dqm->dev->shared_resources.compute_pipe_count;
-}
-
 #endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */
index 6b072466e2a6f628c8a1ff4a026cf5788af65c43..5469efe0523e8d85b11ad33729bfed9036051dfa 100644 (file)
@@ -131,5 +131,5 @@ static int register_process_cik(struct device_queue_manager *dqm,
 
 static int initialize_cpsch_cik(struct device_queue_manager *dqm)
 {
-       return init_pipelines(dqm, get_pipes_num(dqm), 0);
+       return init_pipelines(dqm, get_pipes_num(dqm), get_first_pipe(dqm));
 }
index e415a2a9207eb4605632f91e97e2a271809c04d1..c7d298e62c96bc026154fbe48c4cc7a3828abdb9 100644 (file)
@@ -44,7 +44,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
        BUG_ON(!kq || !dev);
        BUG_ON(type != KFD_QUEUE_TYPE_DIQ && type != KFD_QUEUE_TYPE_HIQ);
 
-       pr_debug("kfd: In func %s initializing queue type %d size %d\n",
+       pr_debug("amdkfd: In func %s initializing queue type %d size %d\n",
                        __func__, KFD_QUEUE_TYPE_HIQ, queue_size);
 
        nop.opcode = IT_NOP;
@@ -69,12 +69,16 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
 
        prop.doorbell_ptr = kfd_get_kernel_doorbell(dev, &prop.doorbell_off);
 
-       if (prop.doorbell_ptr == NULL)
+       if (prop.doorbell_ptr == NULL) {
+               pr_err("amdkfd: error init doorbell");
                goto err_get_kernel_doorbell;
+       }
 
        retval = kfd_gtt_sa_allocate(dev, queue_size, &kq->pq);
-       if (retval != 0)
+       if (retval != 0) {
+               pr_err("amdkfd: error init pq queues size (%d)\n", queue_size);
                goto err_pq_allocate_vidmem;
+       }
 
        kq->pq_kernel_addr = kq->pq->cpu_ptr;
        kq->pq_gpu_addr = kq->pq->gpu_addr;
@@ -165,10 +169,8 @@ err_rptr_allocate_vidmem:
 err_eop_allocate_vidmem:
        kfd_gtt_sa_free(dev, kq->pq);
 err_pq_allocate_vidmem:
-       pr_err("kfd: error init pq\n");
        kfd_release_kernel_doorbell(dev, prop.doorbell_ptr);
 err_get_kernel_doorbell:
-       pr_err("kfd: error init doorbell");
        return false;
 
 }
@@ -187,6 +189,8 @@ static void uninitialize(struct kernel_queue *kq)
        else if (kq->queue->properties.type == KFD_QUEUE_TYPE_DIQ)
                kfd_gtt_sa_free(kq->dev, kq->fence_mem_obj);
 
+       kq->mqd->uninit_mqd(kq->mqd, kq->queue->mqd, kq->queue->mqd_mem_obj);
+
        kfd_gtt_sa_free(kq->dev, kq->rptr_mem);
        kfd_gtt_sa_free(kq->dev, kq->wptr_mem);
        kq->ops_asic_specific.uninitialize(kq);
@@ -211,7 +215,7 @@ static int acquire_packet_buffer(struct kernel_queue *kq,
        queue_address = (unsigned int *)kq->pq_kernel_addr;
        queue_size_dwords = kq->queue->properties.queue_size / sizeof(uint32_t);
 
-       pr_debug("kfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
+       pr_debug("amdkfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
                        __func__, rptr, wptr, queue_address);
 
        available_size = (rptr - 1 - wptr + queue_size_dwords) %
@@ -296,7 +300,7 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
        }
 
        if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
-               pr_err("kfd: failed to init kernel queue\n");
+               pr_err("amdkfd: failed to init kernel queue\n");
                kfree(kq);
                return NULL;
        }
@@ -319,7 +323,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
 
        BUG_ON(!dev);
 
-       pr_err("kfd: starting kernel queue test\n");
+       pr_err("amdkfd: starting kernel queue test\n");
 
        kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ);
        BUG_ON(!kq);
@@ -330,7 +334,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
                buffer[i] = kq->nop_packet;
        kq->ops.submit_packet(kq);
 
-       pr_err("kfd: ending kernel queue test\n");
+       pr_err("amdkfd: ending kernel queue test\n");
 }
 
 
index 0409b907de5d5cc771543d17cc50ed20bad3e3ba..b3e3068c6ec07f8caa8bac6a4edc68e75741190d 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 7320a6c6613f174c1776f75c6dcc832cf91f1ad8..c1cb17493e0d4e212821c832009012c2384c7143 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 063d2a7b941fcaa4f5b527afd41a193fd382d64d..e79bd9ba474b3c181140b0d9f519a96066443acd 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 6b00173d1be4fd6c96f749a803dd23ab5495de88..679b10e34fb545f23c827f9699bfef1c9f4268bd 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 9a5b68717ec8c31fbd27bfa313833b568444fce9..379ab45557568c6e21615526a96a60e145ed1ee5 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 732cb6f8e653f58dee7102f0bb11b797cde2f5ad..4c0aa97aaf0399a111fe0d63be6d996bafbfd7f3 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 04a209e2b66d7d61428398bb5b58b2222ec2a712..1134526286c819c87bc523a1b8852dc485804046 100644 (file)
  */
 
 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
-                                               unsigned long size,
+                                               u64 size,
                                                unsigned alignment,
                                                unsigned long color,
                                                enum drm_mm_search_flags flags);
 static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
-                                               unsigned long size,
+                                               u64 size,
                                                unsigned alignment,
                                                unsigned long color,
-                                               unsigned long start,
-                                               unsigned long end,
+                                               u64 start,
+                                               u64 end,
                                                enum drm_mm_search_flags flags);
 
 static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
                                 struct drm_mm_node *node,
-                                unsigned long size, unsigned alignment,
+                                u64 size, unsigned alignment,
                                 unsigned long color,
                                 enum drm_mm_allocator_flags flags)
 {
        struct drm_mm *mm = hole_node->mm;
-       unsigned long hole_start = drm_mm_hole_node_start(hole_node);
-       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
-       unsigned long adj_start = hole_start;
-       unsigned long adj_end = hole_end;
+       u64 hole_start = drm_mm_hole_node_start(hole_node);
+       u64 hole_end = drm_mm_hole_node_end(hole_node);
+       u64 adj_start = hole_start;
+       u64 adj_end = hole_end;
 
        BUG_ON(node->allocated);
 
@@ -124,12 +124,15 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
                adj_start = adj_end - size;
 
        if (alignment) {
-               unsigned tmp = adj_start % alignment;
-               if (tmp) {
+               u64 tmp = adj_start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem) {
                        if (flags & DRM_MM_CREATE_TOP)
-                               adj_start -= tmp;
+                               adj_start -= rem;
                        else
-                               adj_start += alignment - tmp;
+                               adj_start += alignment - rem;
                }
        }
 
@@ -176,9 +179,9 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
 int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
 {
        struct drm_mm_node *hole;
-       unsigned long end = node->start + node->size;
-       unsigned long hole_start;
-       unsigned long hole_end;
+       u64 end = node->start + node->size;
+       u64 hole_start;
+       u64 hole_end;
 
        BUG_ON(node == NULL);
 
@@ -227,7 +230,7 @@ EXPORT_SYMBOL(drm_mm_reserve_node);
  * 0 on success, -ENOSPC if there's no suitable hole.
  */
 int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
-                              unsigned long size, unsigned alignment,
+                              u64 size, unsigned alignment,
                               unsigned long color,
                               enum drm_mm_search_flags sflags,
                               enum drm_mm_allocator_flags aflags)
@@ -246,16 +249,16 @@ EXPORT_SYMBOL(drm_mm_insert_node_generic);
 
 static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
                                       struct drm_mm_node *node,
-                                      unsigned long size, unsigned alignment,
+                                      u64 size, unsigned alignment,
                                       unsigned long color,
-                                      unsigned long start, unsigned long end,
+                                      u64 start, u64 end,
                                       enum drm_mm_allocator_flags flags)
 {
        struct drm_mm *mm = hole_node->mm;
-       unsigned long hole_start = drm_mm_hole_node_start(hole_node);
-       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
-       unsigned long adj_start = hole_start;
-       unsigned long adj_end = hole_end;
+       u64 hole_start = drm_mm_hole_node_start(hole_node);
+       u64 hole_end = drm_mm_hole_node_end(hole_node);
+       u64 adj_start = hole_start;
+       u64 adj_end = hole_end;
 
        BUG_ON(!hole_node->hole_follows || node->allocated);
 
@@ -271,12 +274,15 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
                mm->color_adjust(hole_node, color, &adj_start, &adj_end);
 
        if (alignment) {
-               unsigned tmp = adj_start % alignment;
-               if (tmp) {
+               u64 tmp = adj_start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem) {
                        if (flags & DRM_MM_CREATE_TOP)
-                               adj_start -= tmp;
+                               adj_start -= rem;
                        else
-                               adj_start += alignment - tmp;
+                               adj_start += alignment - rem;
                }
        }
 
@@ -324,9 +330,9 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
  * 0 on success, -ENOSPC if there's no suitable hole.
  */
 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
-                                       unsigned long size, unsigned alignment,
+                                       u64 size, unsigned alignment,
                                        unsigned long color,
-                                       unsigned long start, unsigned long end,
+                                       u64 start, u64 end,
                                        enum drm_mm_search_flags sflags,
                                        enum drm_mm_allocator_flags aflags)
 {
@@ -387,32 +393,34 @@ void drm_mm_remove_node(struct drm_mm_node *node)
 }
 EXPORT_SYMBOL(drm_mm_remove_node);
 
-static int check_free_hole(unsigned long start, unsigned long end,
-                          unsigned long size, unsigned alignment)
+static int check_free_hole(u64 start, u64 end, u64 size, unsigned alignment)
 {
        if (end - start < size)
                return 0;
 
        if (alignment) {
-               unsigned tmp = start % alignment;
-               if (tmp)
-                       start += alignment - tmp;
+               u64 tmp = start;
+               unsigned rem;
+
+               rem = do_div(tmp, alignment);
+               if (rem)
+                       start += alignment - rem;
        }
 
        return end >= start + size;
 }
 
 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
-                                                     unsigned long size,
+                                                     u64 size,
                                                      unsigned alignment,
                                                      unsigned long color,
                                                      enum drm_mm_search_flags flags)
 {
        struct drm_mm_node *entry;
        struct drm_mm_node *best;
-       unsigned long adj_start;
-       unsigned long adj_end;
-       unsigned long best_size;
+       u64 adj_start;
+       u64 adj_end;
+       u64 best_size;
 
        BUG_ON(mm->scanned_blocks);
 
@@ -421,7 +429,7 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
 
        __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
                               flags & DRM_MM_SEARCH_BELOW) {
-               unsigned long hole_size = adj_end - adj_start;
+               u64 hole_size = adj_end - adj_start;
 
                if (mm->color_adjust) {
                        mm->color_adjust(entry, color, &adj_start, &adj_end);
@@ -445,18 +453,18 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
 }
 
 static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
-                                                       unsigned long size,
+                                                       u64 size,
                                                        unsigned alignment,
                                                        unsigned long color,
-                                                       unsigned long start,
-                                                       unsigned long end,
+                                                       u64 start,
+                                                       u64 end,
                                                        enum drm_mm_search_flags flags)
 {
        struct drm_mm_node *entry;
        struct drm_mm_node *best;
-       unsigned long adj_start;
-       unsigned long adj_end;
-       unsigned long best_size;
+       u64 adj_start;
+       u64 adj_end;
+       u64 best_size;
 
        BUG_ON(mm->scanned_blocks);
 
@@ -465,7 +473,7 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
 
        __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
                               flags & DRM_MM_SEARCH_BELOW) {
-               unsigned long hole_size = adj_end - adj_start;
+               u64 hole_size = adj_end - adj_start;
 
                if (adj_start < start)
                        adj_start = start;
@@ -561,7 +569,7 @@ EXPORT_SYMBOL(drm_mm_replace_node);
  * adding/removing nodes to/from the scan list are allowed.
  */
 void drm_mm_init_scan(struct drm_mm *mm,
-                     unsigned long size,
+                     u64 size,
                      unsigned alignment,
                      unsigned long color)
 {
@@ -594,11 +602,11 @@ EXPORT_SYMBOL(drm_mm_init_scan);
  * adding/removing nodes to/from the scan list are allowed.
  */
 void drm_mm_init_scan_with_range(struct drm_mm *mm,
-                                unsigned long size,
+                                u64 size,
                                 unsigned alignment,
                                 unsigned long color,
-                                unsigned long start,
-                                unsigned long end)
+                                u64 start,
+                                u64 end)
 {
        mm->scan_color = color;
        mm->scan_alignment = alignment;
@@ -627,8 +635,8 @@ bool drm_mm_scan_add_block(struct drm_mm_node *node)
 {
        struct drm_mm *mm = node->mm;
        struct drm_mm_node *prev_node;
-       unsigned long hole_start, hole_end;
-       unsigned long adj_start, adj_end;
+       u64 hole_start, hole_end;
+       u64 adj_start, adj_end;
 
        mm->scanned_blocks++;
 
@@ -731,7 +739,7 @@ EXPORT_SYMBOL(drm_mm_clean);
  *
  * Note that @mm must be cleared to 0 before calling this function.
  */
-void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
+void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
 {
        INIT_LIST_HEAD(&mm->hole_stack);
        mm->scanned_blocks = 0;
@@ -766,18 +774,17 @@ void drm_mm_takedown(struct drm_mm * mm)
 }
 EXPORT_SYMBOL(drm_mm_takedown);
 
-static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
-                                      const char *prefix)
+static u64 drm_mm_debug_hole(struct drm_mm_node *entry,
+                                    const char *prefix)
 {
-       unsigned long hole_start, hole_end, hole_size;
+       u64 hole_start, hole_end, hole_size;
 
        if (entry->hole_follows) {
                hole_start = drm_mm_hole_node_start(entry);
                hole_end = drm_mm_hole_node_end(entry);
                hole_size = hole_end - hole_start;
-               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
-                       prefix, hole_start, hole_end,
-                       hole_size);
+               pr_debug("%s %#llx-%#llx: %llu: free\n", prefix, hole_start,
+                        hole_end, hole_size);
                return hole_size;
        }
 
@@ -792,35 +799,34 @@ static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
 void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
 {
        struct drm_mm_node *entry;
-       unsigned long total_used = 0, total_free = 0, total = 0;
+       u64 total_used = 0, total_free = 0, total = 0;
 
        total_free += drm_mm_debug_hole(&mm->head_node, prefix);
 
        drm_mm_for_each_node(entry, mm) {
-               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
-                       prefix, entry->start, entry->start + entry->size,
-                       entry->size);
+               pr_debug("%s %#llx-%#llx: %llu: used\n", prefix, entry->start,
+                        entry->start + entry->size, entry->size);
                total_used += entry->size;
                total_free += drm_mm_debug_hole(entry, prefix);
        }
        total = total_free + total_used;
 
-       printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total,
-               total_used, total_free);
+       pr_debug("%s total: %llu, used %llu free %llu\n", prefix, total,
+                total_used, total_free);
 }
 EXPORT_SYMBOL(drm_mm_debug_table);
 
 #if defined(CONFIG_DEBUG_FS)
-static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
+static u64 drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
 {
-       unsigned long hole_start, hole_end, hole_size;
+       u64 hole_start, hole_end, hole_size;
 
        if (entry->hole_follows) {
                hole_start = drm_mm_hole_node_start(entry);
                hole_end = drm_mm_hole_node_end(entry);
                hole_size = hole_end - hole_start;
-               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
-                               hole_start, hole_end, hole_size);
+               seq_printf(m, "%#llx-%#llx: %llu: free\n", hole_start,
+                          hole_end, hole_size);
                return hole_size;
        }
 
@@ -835,20 +841,20 @@ static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *en
 int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
 {
        struct drm_mm_node *entry;
-       unsigned long total_used = 0, total_free = 0, total = 0;
+       u64 total_used = 0, total_free = 0, total = 0;
 
        total_free += drm_mm_dump_hole(m, &mm->head_node);
 
        drm_mm_for_each_node(entry, mm) {
-               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
-                               entry->start, entry->start + entry->size,
-                               entry->size);
+               seq_printf(m, "%#016llx-%#016llx: %llu: used\n", entry->start,
+                          entry->start + entry->size, entry->size);
                total_used += entry->size;
                total_free += drm_mm_dump_hole(m, entry);
        }
        total = total_free + total_used;
 
-       seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free);
+       seq_printf(m, "total: %llu, used %llu free %llu\n", total,
+                  total_used, total_free);
        return 0;
 }
 EXPORT_SYMBOL(drm_mm_dump_table);
index 6591d48c1b9d0f3bcc4a74a8da730833cbc4e839..3fee587bc284ebffc7b2050c69034cba9c1949da 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 a5e74612100e4ea02de3ab01ffceef42d8f2f61d..0a6780367d28689f907a4b750f1ee5fc2ef403d9 100644 (file)
@@ -50,7 +50,7 @@ config DRM_EXYNOS_DSI
 
 config DRM_EXYNOS_DP
        bool "EXYNOS DRM DP driver support"
-       depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
+       depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
        default DRM_EXYNOS
        select DRM_PANEL
        help
index 63f02e2380ae1a24746ed87153a1703491f23dff..970046199608484365195ecdd78d27fecc57ed4b 100644 (file)
@@ -888,8 +888,8 @@ static int decon_probe(struct platform_device *pdev)
        of_node_put(i80_if_timings);
 
        ctx->regs = of_iomap(dev->of_node, 0);
-       if (IS_ERR(ctx->regs)) {
-               ret = PTR_ERR(ctx->regs);
+       if (!ctx->regs) {
+               ret = -ENOMEM;
                goto err_del_component;
        }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
deleted file mode 100644 (file)
index ba9b3d5..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Joonyoung Shim <jy0922.shim@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-
-#include <drm/exynos_drm.h>
-#include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
-#include "exynos_drm_connector.h"
-
-#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
-                               drm_connector)
-
-struct exynos_drm_connector {
-       struct drm_connector            drm_connector;
-       uint32_t                        encoder_id;
-       struct exynos_drm_display       *display;
-};
-
-static int exynos_drm_connector_get_modes(struct drm_connector *connector)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       struct edid *edid = NULL;
-       unsigned int count = 0;
-       int ret;
-
-       /*
-        * if get_edid() exists then get_edid() callback of hdmi side
-        * is called to get edid data through i2c interface else
-        * get timing from the FIMD driver(display controller).
-        *
-        * P.S. in case of lcd panel, count is always 1 if success
-        * because lcd panel has only one mode.
-        */
-       if (display->ops->get_edid) {
-               edid = display->ops->get_edid(display, connector);
-               if (IS_ERR_OR_NULL(edid)) {
-                       ret = PTR_ERR(edid);
-                       edid = NULL;
-                       DRM_ERROR("Panel operation get_edid failed %d\n", ret);
-                       goto out;
-               }
-
-               count = drm_add_edid_modes(connector, edid);
-               if (!count) {
-                       DRM_ERROR("Add edid modes failed %d\n", count);
-                       goto out;
-               }
-
-               drm_mode_connector_update_edid_property(connector, edid);
-       } else {
-               struct exynos_drm_panel_info *panel;
-               struct drm_display_mode *mode = drm_mode_create(connector->dev);
-               if (!mode) {
-                       DRM_ERROR("failed to create a new display mode.\n");
-                       return 0;
-               }
-
-               if (display->ops->get_panel)
-                       panel = display->ops->get_panel(display);
-               else {
-                       drm_mode_destroy(connector->dev, mode);
-                       return 0;
-               }
-
-               drm_display_mode_from_videomode(&panel->vm, mode);
-               mode->width_mm = panel->width_mm;
-               mode->height_mm = panel->height_mm;
-               connector->display_info.width_mm = mode->width_mm;
-               connector->display_info.height_mm = mode->height_mm;
-
-               mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-               drm_mode_set_name(mode);
-               drm_mode_probed_add(connector, mode);
-
-               count = 1;
-       }
-
-out:
-       kfree(edid);
-       return count;
-}
-
-static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
-                                           struct drm_display_mode *mode)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       int ret = MODE_BAD;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (display->ops->check_mode)
-               if (!display->ops->check_mode(display, mode))
-                       ret = MODE_OK;
-
-       return ret;
-}
-
-static struct drm_encoder *exynos_drm_best_encoder(
-               struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       return drm_encoder_find(dev, exynos_connector->encoder_id);
-}
-
-static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
-       .get_modes      = exynos_drm_connector_get_modes,
-       .mode_valid     = exynos_drm_connector_mode_valid,
-       .best_encoder   = exynos_drm_best_encoder,
-};
-
-static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
-                               unsigned int max_width, unsigned int max_height)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       unsigned int width, height;
-
-       width = max_width;
-       height = max_height;
-
-       /*
-        * if specific driver want to find desired_mode using maxmum
-        * resolution then get max width and height from that driver.
-        */
-       if (display->ops->get_max_resol)
-               display->ops->get_max_resol(display, &width, &height);
-
-       return drm_helper_probe_single_connector_modes(connector, width,
-                                                       height);
-}
-
-/* get detection status of display device. */
-static enum drm_connector_status
-exynos_drm_connector_detect(struct drm_connector *connector, bool force)
-{
-       struct exynos_drm_connector *exynos_connector =
-                                       to_exynos_connector(connector);
-       struct exynos_drm_display *display = exynos_connector->display;
-       enum drm_connector_status status = connector_status_disconnected;
-
-       if (display->ops->is_connected) {
-               if (display->ops->is_connected(display))
-                       status = connector_status_connected;
-               else
-                       status = connector_status_disconnected;
-       }
-
-       return status;
-}
-
-static void exynos_drm_connector_destroy(struct drm_connector *connector)
-{
-       struct exynos_drm_connector *exynos_connector =
-               to_exynos_connector(connector);
-
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-       kfree(exynos_connector);
-}
-
-static struct drm_connector_funcs exynos_connector_funcs = {
-       .dpms           = drm_helper_connector_dpms,
-       .fill_modes     = exynos_drm_connector_fill_modes,
-       .detect         = exynos_drm_connector_detect,
-       .destroy        = exynos_drm_connector_destroy,
-};
-
-struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
-                                                  struct drm_encoder *encoder)
-{
-       struct exynos_drm_connector *exynos_connector;
-       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
-       struct drm_connector *connector;
-       int type;
-       int err;
-
-       exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
-       if (!exynos_connector)
-               return NULL;
-
-       connector = &exynos_connector->drm_connector;
-
-       switch (display->type) {
-       case EXYNOS_DISPLAY_TYPE_HDMI:
-               type = DRM_MODE_CONNECTOR_HDMIA;
-               connector->interlace_allowed = true;
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-               break;
-       case EXYNOS_DISPLAY_TYPE_VIDI:
-               type = DRM_MODE_CONNECTOR_VIRTUAL;
-               connector->polled = DRM_CONNECTOR_POLL_HPD;
-               break;
-       default:
-               type = DRM_MODE_CONNECTOR_Unknown;
-               break;
-       }
-
-       drm_connector_init(dev, connector, &exynos_connector_funcs, type);
-       drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
-
-       err = drm_connector_register(connector);
-       if (err)
-               goto err_connector;
-
-       exynos_connector->encoder_id = encoder->base.id;
-       exynos_connector->display = display;
-       connector->dpms = DRM_MODE_DPMS_OFF;
-       connector->encoder = encoder;
-
-       err = drm_mode_connector_attach_encoder(connector, encoder);
-       if (err) {
-               DRM_ERROR("failed to attach a connector to a encoder\n");
-               goto err_sysfs;
-       }
-
-       DRM_DEBUG_KMS("connector has been created\n");
-
-       return connector;
-
-err_sysfs:
-       drm_connector_unregister(connector);
-err_connector:
-       drm_connector_cleanup(connector);
-       kfree(exynos_connector);
-       return NULL;
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h
deleted file mode 100644 (file)
index 4eb20d7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Joonyoung Shim <jy0922.shim@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_CONNECTOR_H_
-#define _EXYNOS_DRM_CONNECTOR_H_
-
-struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
-                                                  struct drm_encoder *encoder);
-
-#endif
index 925fc69af1a0c28a083171cdba563537ee3741da..33a10ce967eacdfbcbc679a8645baae4515b4f1b 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 a5616872eee7f9defdebe63025b9e92f10060fc7..8ad5b7294eb4801c189fa3b2cdf90ebb24606fd3 100644 (file)
@@ -175,7 +175,7 @@ static int exynos_disable_plane(struct drm_plane *plane)
        struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc);
 
-       if (exynos_crtc->ops->win_disable)
+       if (exynos_crtc && exynos_crtc->ops->win_disable)
                exynos_crtc->ops->win_disable(exynos_crtc,
                                              exynos_plane->zpos);
 
index 3518bc4654c5c9381acdb8d7253395e0466c8adc..2e3bc57ea50e594dcdf739042c39169428ecbda1 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 96e811fe24ca79cd1b6438591cf1eb05379f0edd..e8b18e542da4311169a4b0ec6c6f45fe73a711cd 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 8039cec71fc24a3750812dc519b08bee6a824f41..cc6ea53d2b81951553d4b135a1760cb127e574c2 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 f2a825e39646427b7e4617627bd8ab3c3b9acb4d..8727086cf48ccce9e6548df8cf4e1d0df59012e7 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 c26d36cc4b313ac4d03ade4167739d7fd7be6e9c..27ea6bdebce761dbd8dca5340a4cd6e2bd32eaa3 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 b773368fc62c8ac67717f6770ce20fd642a1bc8c..38a742532c4fa48ba2798d6aec910b546839090f 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 746f77fb57a314d5b94542b12b67b7a16bfb50eb..dccdc8aad2e24c2351766a1ec591f5a57dd3940b 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 a2045848bd1a3d5d37c299d34b7e19dce50173d7..9c6f93ec886b7023b0ce8fa2753bacaaf041aaff 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 7a24bd1a51f648b340ce15d5ee98771cd1fd77d9..6377b22269ad1e7157058baf1447cb548362306c 100644 (file)
@@ -335,9 +335,10 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
+       mutex_lock(&dev->struct_mutex);
        if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto err;
        }
 
        if (args->tiling_mode == I915_TILING_NONE) {
@@ -369,7 +370,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                }
        }
 
-       mutex_lock(&dev->struct_mutex);
        if (args->tiling_mode != obj->tiling_mode ||
            args->stride != obj->stride) {
                /* We need to rebind the object if its current allocation
@@ -424,6 +424,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                obj->bit_17 = NULL;
        }
 
+err:
        drm_gem_object_unreference(&obj->base);
        mutex_unlock(&dev->struct_mutex);
 
index 4145d95902f54fbd9fb4f92668fe10fde2b330a0..ede5bbbd8a08a175873e24215a754b5be28ef23d 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 3d220a67f8656ed9173b88672cd114893070aec0..f75173c20f47677f1a8462dabc78b10ac7b4645f 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 04e248dd2259715426e8ad82b817b59d3634b24a..54daa66c697077f5b0609ddb5eec0d7989db780a 100644 (file)
@@ -282,16 +282,6 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
        return ret;
 }
 
-static bool
-__cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
-                                     enum pipe pipe)
-{
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-       return !intel_crtc->cpu_fifo_underrun_disabled;
-}
-
 /**
  * intel_set_pch_fifo_underrun_reporting - set PCH fifo underrun reporting state
  * @dev_priv: i915 device instance
@@ -352,9 +342,15 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
 void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
                                         enum pipe pipe)
 {
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+       /* We may be called too early in init, thanks BIOS! */
+       if (crtc == NULL)
+               return;
+
        /* GMCH can't disable fifo underruns, filter them. */
        if (HAS_GMCH_DISPLAY(dev_priv->dev) &&
-           !__cpu_fifo_underrun_reporting_enabled(dev_priv, pipe))
+           to_intel_crtc(crtc)->cpu_fifo_underrun_disabled)
                return;
 
        if (intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false))
index 0f358c5999ec8e0c8771a3d932447d281748a8b1..e8d3da9f337388e5a1647766a61281e4d25aa22d 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 0a52c44ad03d6b21078fe7482ddc3b84813ac9c4..9c5451c97942801544bbe9a0e692810bb5a9444e 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 c47a3baa53d5963cdfc1663320ac2e88398f276d..4e8fb891d4eac88a4bbc3f68dcd01749948d13d6 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 121d30ca2d4448f379c743ac781bb9910ccd2d44..87fe8ed92ebeb8bf996fb95b79731dbebdbed2dd 100644 (file)
@@ -70,7 +70,9 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
                118800000, { 0x091c, 0x091c, 0x06dc },
        }, {
                216000000, { 0x06dc, 0x0b5c, 0x091c },
-       }
+       }, {
+               ~0UL, { 0x0000, 0x0000, 0x0000 },
+       },
 };
 
 static const struct dw_hdmi_sym_term imx_sym_term[] = {
@@ -136,11 +138,34 @@ static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
        .destroy = drm_encoder_cleanup,
 };
 
+static enum drm_mode_status imx6q_hdmi_mode_valid(struct drm_connector *con,
+                                                 struct drm_display_mode *mode)
+{
+       if (mode->clock < 13500)
+               return MODE_CLOCK_LOW;
+       if (mode->clock > 266000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,
+                                                  struct drm_display_mode *mode)
+{
+       if (mode->clock < 13500)
+               return MODE_CLOCK_LOW;
+       if (mode->clock > 270000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
 static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
-       .mpll_cfg = imx_mpll_cfg,
-       .cur_ctr  = imx_cur_ctr,
-       .sym_term = imx_sym_term,
-       .dev_type = IMX6Q_HDMI,
+       .mpll_cfg   = imx_mpll_cfg,
+       .cur_ctr    = imx_cur_ctr,
+       .sym_term   = imx_sym_term,
+       .dev_type   = IMX6Q_HDMI,
+       .mode_valid = imx6q_hdmi_mode_valid,
 };
 
 static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
@@ -148,6 +173,7 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
        .cur_ctr  = imx_cur_ctr,
        .sym_term = imx_sym_term,
        .dev_type = IMX6DL_HDMI,
+       .mode_valid = imx6dl_hdmi_mode_valid,
 };
 
 static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
index 1b86aac0b341c7083b15e03163338989a1543592..2d6dc94e1e64e973f61a1294c24bba6d2d788ae2 100644 (file)
@@ -163,22 +163,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
 {
        struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
        struct imx_ldb *ldb = imx_ldb_ch->ldb;
-       struct drm_display_mode *mode = &encoder->crtc->hwmode;
        u32 pixel_fmt;
-       unsigned long serial_clk;
-       unsigned long di_clk = mode->clock * 1000;
-       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
-
-       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-               /* dual channel LVDS mode */
-               serial_clk = 3500UL * mode->clock;
-               imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
-               imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
-       } else {
-               serial_clk = 7000UL * mode->clock;
-               imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
-                               di_clk);
-       }
 
        switch (imx_ldb_ch->chno) {
        case 0:
@@ -247,6 +232,9 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
        struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
        struct imx_ldb *ldb = imx_ldb_ch->ldb;
        int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
+       unsigned long serial_clk;
+       unsigned long di_clk = mode->clock * 1000;
+       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
 
        if (mode->clock > 170000) {
                dev_warn(ldb->dev,
@@ -257,6 +245,16 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
                         "%s: mode exceeds 85 MHz pixel clock\n", __func__);
        }
 
+       if (dual) {
+               serial_clk = 3500UL * mode->clock;
+               imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
+               imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
+       } else {
+               serial_clk = 7000UL * mode->clock;
+               imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
+                                 di_clk);
+       }
+
        /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
        if (imx_ldb_ch == &ldb->channel[0]) {
                if (mode->flags & DRM_MODE_FLAG_NVSYNC)
index 5e83e007080f7ae757b3f6c567cd791a595bd9d1..900dda6a8e71b5501293b8d4be06ddb8288dee27 100644 (file)
@@ -236,8 +236,11 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
        }
 
        panel_node = of_parse_phandle(np, "fsl,panel", 0);
-       if (panel_node)
+       if (panel_node) {
                imxpd->panel = of_drm_find_panel(panel_node);
+               if (!imxpd->panel)
+                       return -EPROBE_DEFER;
+       }
 
        imxpd->dev = dev;
 
index 8edd531cb62166ad1291be18ffc26ba033cbc71d..7369ee7f0c5544a6c44b9850e4ded92217da2596 100644 (file)
@@ -32,7 +32,10 @@ static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
 void mdp4_irq_preinstall(struct msm_kms *kms)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_enable(mdp4_kms);
        mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff);
+       mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+       mdp4_disable(mdp4_kms);
 }
 
 int mdp4_irq_postinstall(struct msm_kms *kms)
@@ -53,7 +56,9 @@ int mdp4_irq_postinstall(struct msm_kms *kms)
 void mdp4_irq_uninstall(struct msm_kms *kms)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_enable(mdp4_kms);
        mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+       mdp4_disable(mdp4_kms);
 }
 
 irqreturn_t mdp4_irq(struct msm_kms *kms)
index 09b4a25eb553fa9cad7f68ad8a61afa13a8d90a0..c276624290afedb3f8de9fe9db2ed9271cab5ff4 100644 (file)
@@ -8,17 +8,9 @@ http://github.com/freedreno/envytools/
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml            (  27229 bytes, from 2015-02-10 17:00:41)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2014-06-02 18:31:15)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2015-01-23 16:20:19)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -910,6 +902,7 @@ static inline uint32_t __offset_LM(uint32_t idx)
                case 2: return (mdp5_cfg->lm.base[2]);
                case 3: return (mdp5_cfg->lm.base[3]);
                case 4: return (mdp5_cfg->lm.base[4]);
+               case 5: return (mdp5_cfg->lm.base[5]);
                default: return INVALID_IDX(idx);
        }
 }
index 46fac545dc2bb8f84e8d6bc241d88931d926b23e..2f2863cf8b45f21e692e3e50f09c88275d83da63 100644 (file)
@@ -62,8 +62,8 @@ struct mdp5_crtc {
 
                /* current cursor being scanned out: */
                struct drm_gem_object *scanout_bo;
-               uint32_t width;
-               uint32_t height;
+               uint32_t width, height;
+               uint32_t x, y;
        } cursor;
 };
 #define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
@@ -103,8 +103,8 @@ static void crtc_flush_all(struct drm_crtc *crtc)
        struct drm_plane *plane;
        uint32_t flush_mask = 0;
 
-       /* we could have already released CTL in the disable path: */
-       if (!mdp5_crtc->ctl)
+       /* this should not happen: */
+       if (WARN_ON(!mdp5_crtc->ctl))
                return;
 
        drm_atomic_crtc_for_each_plane(plane, crtc) {
@@ -143,6 +143,11 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
        drm_atomic_crtc_for_each_plane(plane, crtc) {
                mdp5_plane_complete_flip(plane);
        }
+
+       if (mdp5_crtc->ctl && !crtc->state->enable) {
+               mdp5_ctl_release(mdp5_crtc->ctl);
+               mdp5_crtc->ctl = NULL;
+       }
 }
 
 static void unref_cursor_worker(struct drm_flip_work *work, void *val)
@@ -386,14 +391,17 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
        mdp5_crtc->event = crtc->state->event;
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
+       /*
+        * If no CTL has been allocated in mdp5_crtc_atomic_check(),
+        * it means we are trying to flush a CRTC whose state is disabled:
+        * nothing else needs to be done.
+        */
+       if (unlikely(!mdp5_crtc->ctl))
+               return;
+
        blend_setup(crtc);
        crtc_flush_all(crtc);
        request_pending(crtc, PENDING_FLIP);
-
-       if (mdp5_crtc->ctl && !crtc->state->enable) {
-               mdp5_ctl_release(mdp5_crtc->ctl);
-               mdp5_crtc->ctl = NULL;
-       }
 }
 
 static int mdp5_crtc_set_property(struct drm_crtc *crtc,
@@ -403,6 +411,32 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
        return -EINVAL;
 }
 
+static void get_roi(struct drm_crtc *crtc, uint32_t *roi_w, uint32_t *roi_h)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       uint32_t xres = crtc->mode.hdisplay;
+       uint32_t yres = crtc->mode.vdisplay;
+
+       /*
+        * Cursor Region Of Interest (ROI) is a plane read from cursor
+        * buffer to render. The ROI region is determined by the visibility of
+        * the cursor point. In the default Cursor image the cursor point will
+        * be at the top left of the cursor image, unless it is specified
+        * otherwise using hotspot feature.
+        *
+        * If the cursor point reaches the right (xres - x < cursor.width) or
+        * bottom (yres - y < cursor.height) boundary of the screen, then ROI
+        * width and ROI height need to be evaluated to crop the cursor image
+        * accordingly.
+        * (xres-x) will be new cursor width when x > (xres - cursor.width)
+        * (yres-y) will be new cursor height when y > (yres - cursor.height)
+        */
+       *roi_w = min(mdp5_crtc->cursor.width, xres -
+                       mdp5_crtc->cursor.x);
+       *roi_h = min(mdp5_crtc->cursor.height, yres -
+                       mdp5_crtc->cursor.y);
+}
+
 static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
                struct drm_file *file, uint32_t handle,
                uint32_t width, uint32_t height)
@@ -416,6 +450,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        unsigned int depth;
        enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+       uint32_t roi_w, roi_h;
        unsigned long flags;
 
        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
@@ -446,6 +481,12 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
        old_bo = mdp5_crtc->cursor.scanout_bo;
 
+       mdp5_crtc->cursor.scanout_bo = cursor_bo;
+       mdp5_crtc->cursor.width = width;
+       mdp5_crtc->cursor.height = height;
+
+       get_roi(crtc, &roi_w, &roi_h);
+
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
                        MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
@@ -453,19 +494,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
                        MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
                        MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
-                       MDP5_LM_CURSOR_SIZE_ROI_H(height) |
-                       MDP5_LM_CURSOR_SIZE_ROI_W(width));
+                       MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
+                       MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), cursor_addr);
 
-
        blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
-       blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN;
        blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
 
-       mdp5_crtc->cursor.scanout_bo = cursor_bo;
-       mdp5_crtc->cursor.width = width;
-       mdp5_crtc->cursor.height = height;
        spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
 
        ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
@@ -489,31 +525,18 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
-       uint32_t xres = crtc->mode.hdisplay;
-       uint32_t yres = crtc->mode.vdisplay;
        uint32_t roi_w;
        uint32_t roi_h;
        unsigned long flags;
 
-       x = (x > 0) ? x : 0;
-       y = (y > 0) ? y : 0;
+       /* In case the CRTC is disabled, just drop the cursor update */
+       if (unlikely(!crtc->state->enable))
+               return 0;
 
-       /*
-        * Cursor Region Of Interest (ROI) is a plane read from cursor
-        * buffer to render. The ROI region is determined by the visiblity of
-        * the cursor point. In the default Cursor image the cursor point will
-        * be at the top left of the cursor image, unless it is specified
-        * otherwise using hotspot feature.
-        *
-        * If the cursor point reaches the right (xres - x < cursor.width) or
-        * bottom (yres - y < cursor.height) boundary of the screen, then ROI
-        * width and ROI height need to be evaluated to crop the cursor image
-        * accordingly.
-        * (xres-x) will be new cursor width when x > (xres - cursor.width)
-        * (yres-y) will be new cursor height when y > (yres - cursor.height)
-        */
-       roi_w = min(mdp5_crtc->cursor.width, xres - x);
-       roi_h = min(mdp5_crtc->cursor.height, yres - y);
+       mdp5_crtc->cursor.x = x = max(x, 0);
+       mdp5_crtc->cursor.y = y = max(y, 0);
+
+       get_roi(crtc, &roi_w, &roi_h);
 
        spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
        mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(mdp5_crtc->lm),
@@ -544,8 +567,8 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = {
 static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
        .mode_fixup = mdp5_crtc_mode_fixup,
        .mode_set_nofb = mdp5_crtc_mode_set_nofb,
-       .prepare = mdp5_crtc_disable,
-       .commit = mdp5_crtc_enable,
+       .disable = mdp5_crtc_disable,
+       .enable = mdp5_crtc_enable,
        .atomic_check = mdp5_crtc_atomic_check,
        .atomic_begin = mdp5_crtc_atomic_begin,
        .atomic_flush = mdp5_crtc_atomic_flush,
index d6a14bb99988199db0993dd654255eecf2269539..af0e02fa4f4821ac7a71a4b641fde76db366a8cd 100644 (file)
@@ -267,14 +267,14 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
        mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
 
-       mdp5_encoder->enabled = false;
+       mdp5_encoder->enabled = true;
 }
 
 static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
        .mode_fixup = mdp5_encoder_mode_fixup,
        .mode_set = mdp5_encoder_mode_set,
-       .prepare = mdp5_encoder_disable,
-       .commit = mdp5_encoder_enable,
+       .disable = mdp5_encoder_disable,
+       .enable = mdp5_encoder_enable,
 };
 
 /* initialize encoder */
index 70ac81edd40f3bb7d6de68553b7be350005312ec..a9407105b9b799bea9fc787a923e7dc914bee30a 100644 (file)
@@ -34,7 +34,10 @@ static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
 void mdp5_irq_preinstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       mdp5_enable(mdp5_kms);
        mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
+       mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_disable(mdp5_kms);
 }
 
 int mdp5_irq_postinstall(struct msm_kms *kms)
@@ -57,7 +60,9 @@ int mdp5_irq_postinstall(struct msm_kms *kms)
 void mdp5_irq_uninstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       mdp5_enable(mdp5_kms);
        mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_disable(mdp5_kms);
 }
 
 static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
index 871aa2108dc694795e74f2b308031c849ad1a966..18fd643b6e6915c3a2e13c149640d9917459eb12 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 79924e4b1b495577f26822f8f03801b67e4497a6..6751553abe4afe4bc408cd08863a7981b858bece 100644 (file)
@@ -418,7 +418,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
        nouveau_fbcon_zfill(dev, fbcon);
 
        /* To allow resizeing without swapping buffers */
-       NV_INFO(drm, "allocated %dx%d fb: 0x%lx, bo %p\n",
+       NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n",
                nouveau_fb->base.width, nouveau_fb->base.height,
                nvbo->bo.offset, nvbo);
 
index 29bd539af183d6d366ef2cafd79c8a5b0ad49ea9..6efa8f38ff5472b42ec9895c7a5505c9992a50c1 100644 (file)
@@ -340,11 +340,13 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 
                /* switch mmio to cpu's native endianness */
 #ifndef __BIG_ENDIAN
-               if (ioread32_native(map + 0x000004) != 0x00000000)
+               if (ioread32_native(map + 0x000004) != 0x00000000) {
 #else
-               if (ioread32_native(map + 0x000004) == 0x00000000)
+               if (ioread32_native(map + 0x000004) == 0x00000000) {
 #endif
                        iowrite32_native(0x01000001, map + 0x000004);
+                       ioread32_native(map);
+               }
 
                /* read boot0 and strapping information */
                boot0 = ioread32_native(map + 0x000000);
index 539561ed3281a1602348eb375b2c698ddb8f7afd..108d048da7643f0b97255edf06e205a72d672a48 100644 (file)
@@ -140,6 +140,49 @@ gm100_identify(struct nvkm_device *device)
                device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
                device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
                device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+#endif
+               break;
+       case 0x126:
+               device->cname = "GM206";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] =  gm204_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
+#if 0
+               /* looks to be some non-trivial changes */
+               device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+               /* priv ring says no to 0x10eb14 writes */
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
+#endif
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm204_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PMU    ] =  gk208_pmu_oclass;
+#if 0
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_CE0    ] = &gm204_ce0_oclass;
+               device->oclass[NVDEV_ENGINE_CE1    ] = &gm204_ce1_oclass;
+               device->oclass[NVDEV_ENGINE_CE2    ] = &gm204_ce2_oclass;
+               device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+               device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+               device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
 #endif
                break;
        default:
index b038b6eb51db2f3104dea58562d14913f4c794ed..043e4296084c176695f6e39ff0f046bbe033b1c0 100644 (file)
@@ -502,72 +502,57 @@ nv04_fifo_intr(struct nvkm_subdev *subdev)
 {
        struct nvkm_device *device = nv_device(subdev);
        struct nv04_fifo_priv *priv = (void *)subdev;
-       uint32_t status, reassign;
-       int cnt = 0;
+       u32 mask = nv_rd32(priv, NV03_PFIFO_INTR_EN_0);
+       u32 stat = nv_rd32(priv, NV03_PFIFO_INTR_0) & mask;
+       u32 reassign, chid, get, sem;
 
        reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
-       while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
-               uint32_t chid, get;
-
-               nv_wr32(priv, NV03_PFIFO_CACHES, 0);
-
-               chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
-               get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
+       nv_wr32(priv, NV03_PFIFO_CACHES, 0);
 
-               if (status & NV_PFIFO_INTR_CACHE_ERROR) {
-                       nv04_fifo_cache_error(device, priv, chid, get);
-                       status &= ~NV_PFIFO_INTR_CACHE_ERROR;
-               }
+       chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+       get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
 
-               if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-                       nv04_fifo_dma_pusher(device, priv, chid);
-                       status &= ~NV_PFIFO_INTR_DMA_PUSHER;
-               }
+       if (stat & NV_PFIFO_INTR_CACHE_ERROR) {
+               nv04_fifo_cache_error(device, priv, chid, get);
+               stat &= ~NV_PFIFO_INTR_CACHE_ERROR;
+       }
 
-               if (status & NV_PFIFO_INTR_SEMAPHORE) {
-                       uint32_t sem;
+       if (stat & NV_PFIFO_INTR_DMA_PUSHER) {
+               nv04_fifo_dma_pusher(device, priv, chid);
+               stat &= ~NV_PFIFO_INTR_DMA_PUSHER;
+       }
 
-                       status &= ~NV_PFIFO_INTR_SEMAPHORE;
-                       nv_wr32(priv, NV03_PFIFO_INTR_0,
-                               NV_PFIFO_INTR_SEMAPHORE);
+       if (stat & NV_PFIFO_INTR_SEMAPHORE) {
+               stat &= ~NV_PFIFO_INTR_SEMAPHORE;
+               nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE);
 
-                       sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
-                       nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+               sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
+               nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
 
-                       nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
-                       nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-               }
+               nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+               nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+       }
 
-               if (device->card_type == NV_50) {
-                       if (status & 0x00000010) {
-                               status &= ~0x00000010;
-                               nv_wr32(priv, 0x002100, 0x00000010);
-                       }
-
-                       if (status & 0x40000000) {
-                               nv_wr32(priv, 0x002100, 0x40000000);
-                               nvkm_fifo_uevent(&priv->base);
-                               status &= ~0x40000000;
-                       }
+       if (device->card_type == NV_50) {
+               if (stat & 0x00000010) {
+                       stat &= ~0x00000010;
+                       nv_wr32(priv, 0x002100, 0x00000010);
                }
 
-               if (status) {
-                       nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
-                               status, chid);
-                       nv_wr32(priv, NV03_PFIFO_INTR_0, status);
-                       status = 0;
+               if (stat & 0x40000000) {
+                       nv_wr32(priv, 0x002100, 0x40000000);
+                       nvkm_fifo_uevent(&priv->base);
+                       stat &= ~0x40000000;
                }
-
-               nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
        }
 
-       if (status) {
-               nv_error(priv, "still angry after %d spins, halt\n", cnt);
-               nv_wr32(priv, 0x002140, 0);
-               nv_wr32(priv, 0x000140, 0);
+       if (stat) {
+               nv_warn(priv, "unknown intr 0x%08x\n", stat);
+               nv_mask(priv, NV03_PFIFO_INTR_EN_0, stat, 0x00000000);
+               nv_wr32(priv, NV03_PFIFO_INTR_0, stat);
        }
 
-       nv_wr32(priv, 0x000100, 0x00000100);
+       nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
 }
 
 static int
index 2e7ec389eea7903e1480fce2b0a8901f6e8f1b4f..57e2c5b1312385ab1cf1a52b776f6b1170102bae 100644 (file)
@@ -1032,9 +1032,9 @@ gf100_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418808, 0x00000000, s, b);
-       mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s));
 }
 
 void
index b52300d8861a760b323fc00a89dd90c3e86738af..5e9454ba158fe816e7c381e7518a259efb1565d8 100644 (file)
@@ -851,9 +851,9 @@ gk104_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418808, 0x00000000, s, b);
-       mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s));
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
index 956f4dce960c7912837c9e16889f6b3db4f6819d..b2fae6e389e24260bb5093ffdd9fa5d90982f277 100644 (file)
@@ -871,9 +871,9 @@ gm107_grctx_generate_bundle(struct gf100_grctx *info)
        const int s = 8;
        const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
        mmio_refn(info, 0x408004, 0x00000000, s, b);
-       mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s));
        mmio_refn(info, 0x418e24, 0x00000000, s, b);
-       mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b);
+       mmio_wr32(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s));
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
index d1a89b2bd5c17393d08e441fb2fbeb643fdf5ff1..c4e1f085ee10b810c07ef1557a9438ac6a1eaa77 100644 (file)
@@ -74,7 +74,11 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info)
        u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
        if (ent) {
                if (ver >= 0x41) {
-                       if (!(nv_ro32(bios, ent) & 0x80000000))
+                       u32 ent_value = nv_ro32(bios, ent);
+                       u8 i2c_port = (ent_value >> 27) & 0x1f;
+                       u8 dpaux_port = (ent_value >> 22) & 0x1f;
+                       /* value 0x1f means unused according to DCB 4.x spec */
+                       if (i2c_port == 0x1f && dpaux_port == 0x1f)
                                info->type = DCB_I2C_UNUSED;
                        else
                                info->type = DCB_I2C_PMGR;
index ed644a4f6f57c4254349c3881a16955cd42cbc05..86807ee91bd13a7640f5b925aa4b5a4c0d9d615d 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 5bf825dfaa098ec6b6ad8f479856ce676f51ba21..8d74de82456e880cb01d7e8132cf6c1caf5fa864 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 7c9df1eac065948df99491b3819427e32ad425d7..c39c1d0d9d4e328d8df7f19caf2b52c68b1988b3 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 e6a4ba236c703dc812d8bc57035408cb9ac5821f..3e670d344a2047151e289ab7dce348001ddf4280 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 03003f8a6de63ba00c741824c053070a009cd319..243a36c93b8f96c0f268ef9bfcae1721043c7240 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 192c8038915187df6714fbd6d653f57dba449c13..3adc2afe32aa6be372abcdd925001bbc79176745 100644 (file)
@@ -26,6 +26,9 @@
 #include "radeon_audio.h"
 #include "sid.h"
 
+#define DCE8_DCCG_AUDIO_DTO1_PHASE     0x05b8
+#define DCE8_DCCG_AUDIO_DTO1_MODULE    0x05bc
+
 u32 dce6_endpoint_rreg(struct radeon_device *rdev,
                              u32 block_offset, u32 reg)
 {
@@ -252,72 +255,67 @@ void dce6_audio_enable(struct radeon_device *rdev,
 void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
        struct radeon_crtc *crtc, unsigned int clock)
 {
-    /* Two dtos; generally use dto0 for HDMI */
+       /* Two dtos; generally use dto0 for HDMI */
        u32 value = 0;
 
-    if (crtc)
+       if (crtc)
                value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
        WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
-    /* Express [24MHz / target pixel clock] as an exact rational
-     * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
-     * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
-     */
-    WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
-    WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
+       /* Express [24MHz / target pixel clock] as an exact rational
+        * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+        * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+        */
+       WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
+       WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
 }
 
 void dce6_dp_audio_set_dto(struct radeon_device *rdev,
        struct radeon_crtc *crtc, unsigned int clock)
 {
-    /* Two dtos; generally use dto1 for DP */
+       /* Two dtos; generally use dto1 for DP */
        u32 value = 0;
        value |= DCCG_AUDIO_DTO_SEL;
 
-    if (crtc)
+       if (crtc)
                value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
        WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
-    /* Express [24MHz / target pixel clock] as an exact rational
-     * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
-     * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
-     */
-    WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
-    WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+       /* Express [24MHz / target pixel clock] as an exact rational
+        * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+        * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+        */
+       if (ASIC_IS_DCE8(rdev)) {
+               WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000);
+               WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock);
+       } else {
+               WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
+               WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+       }
 }
 
-void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+void dce6_dp_enable(struct drm_encoder *encoder, bool enable)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       uint32_t offset;
 
        if (!dig || !dig->afmt)
                return;
 
-       offset = dig->afmt->offset;
-
        if (enable) {
-        if (dig->afmt->enabled)
-            return;
-
-               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset,
-                       EVERGREEN_DP_SEC_ASP_ENABLE |           /* Audio packet transmission */
-                       EVERGREEN_DP_SEC_ATP_ENABLE |           /* Audio timestamp packet transmission */
-                       EVERGREEN_DP_SEC_AIP_ENABLE |           /* Audio infoframe packet transmission */
-                       EVERGREEN_DP_SEC_STREAM_ENABLE);        /* Master enable for secondary stream engine */
-               radeon_audio_enable(rdev, dig->afmt->pin, true);
+               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_ASP_ENABLE |            /* Audio packet transmission */
+                      EVERGREEN_DP_SEC_ATP_ENABLE |            /* Audio timestamp packet transmission */
+                      EVERGREEN_DP_SEC_AIP_ENABLE |            /* Audio infoframe packet transmission */
+                      EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */
        } else {
-               if (!dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
-               radeon_audio_enable(rdev, dig->afmt->pin, false);
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
index 78600f534c804b745b99f7aea8688381b4204182..973df064c14feb193a81c99109665c2186d03dc6 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 1d9aebc79595d050dd52d6e28da01939b908bc16..c18d4ecbd95d02baa907d4d15b6da43f282f4e67 100644 (file)
@@ -272,7 +272,7 @@ void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
 }
 
 void dce4_dp_audio_set_dto(struct radeon_device *rdev,
-       struct radeon_crtc *crtc, unsigned int clock)
+                          struct radeon_crtc *crtc, unsigned int clock)
 {
        u32 value;
 
@@ -294,7 +294,7 @@ void dce4_dp_audio_set_dto(struct radeon_device *rdev,
         * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
         */
        WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
-       WREG32(DCCG_AUDIO_DTO1_MODULE, rdev->clock.max_pixel_clock * 10);
+       WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
 }
 
 void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
@@ -350,20 +350,9 @@ void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
 
-       WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
-               HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
-               HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
-
        WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
                AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
 
-       WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
-               HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
-
-       WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
-               HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
-               HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
-
        WREG32(AFMT_60958_0 + offset,
                AFMT_60958_CS_CHANNEL_NUMBER_L(1));
 
@@ -408,15 +397,19 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!dig || !dig->afmt)
                return;
 
-       /* Silent, r600_hdmi_enable will raise WARN for us */
-       if (enable && dig->afmt->enabled)
-               return;
-       if (!enable && !dig->afmt->enabled)
-               return;
+       if (enable) {
+               WREG32(HDMI_INFOFRAME_CONTROL1 + dig->afmt->offset,
+                      HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
+
+               WREG32(HDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset,
+                      HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
+                      HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
 
-       if (!enable && dig->afmt->pin) {
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
-               dig->afmt->pin = NULL;
+               WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset,
+                      HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+                      HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
+       } else {
+               WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
@@ -425,33 +418,28 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
                  enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
 }
 
-void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+void evergreen_dp_enable(struct drm_encoder *encoder, bool enable)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       uint32_t offset;
 
        if (!dig || !dig->afmt)
                return;
 
-       offset = dig->afmt->offset;
-
        if (enable) {
                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                struct radeon_connector_atom_dig *dig_connector;
                uint32_t val;
 
-               if (dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+               WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset,
+                      EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
 
                if (radeon_connector->con_priv) {
                        dig_connector = radeon_connector->con_priv;
-                       val = RREG32(EVERGREEN_DP_SEC_AUD_N + offset);
+                       val = RREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset);
                        val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf);
 
                        if (dig_connector->dp_clock == 162000)
@@ -459,21 +447,16 @@ void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
                        else
                                val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5);
 
-                       WREG32(EVERGREEN_DP_SEC_AUD_N + offset, val);
+                       WREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset, val);
                }
 
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset,
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset,
                        EVERGREEN_DP_SEC_ASP_ENABLE |           /* Audio packet transmission */
                        EVERGREEN_DP_SEC_ATP_ENABLE |           /* Audio timestamp packet transmission */
                        EVERGREEN_DP_SEC_AIP_ENABLE |           /* Audio infoframe packet transmission */
                        EVERGREEN_DP_SEC_STREAM_ENABLE);        /* Master enable for secondary stream engine */
-               radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
        } else {
-               if (!dig->afmt->enabled)
-                       return;
-
-               WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
+               WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0);
        }
 
        dig->afmt->enabled = enable;
index ee83d2a88750aafb865c30dd89e42c2041700a61..a8d1d5240fcb3088d1ea391ebcc8955c46f8c237 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 24242a7f0ac3d728c4c69366f8af1077ecc25190..dab00812abaabeeeee6295041e730143c99fecba 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 ad7125486894d18ae90b0bc507d248d92baaf3e6..6b44580440d09a10053abcb53bf6f6c048d4e063 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 279801ca5110aff68d80ea452751d7f9b0bf748f..04f2514f756453bfdc7275a52c65549e631cfc6c 100644 (file)
@@ -728,6 +728,10 @@ int r100_irq_set(struct radeon_device *rdev)
                tmp |= RADEON_FP2_DETECT_MASK;
        }
        WREG32(RADEON_GEN_INT_CNTL, tmp);
+
+       /* read back to post the write */
+       RREG32(RADEON_GEN_INT_CNTL);
+
        return 0;
 }
 
index 07a71a2488c93404f0803e3fbefe4c6204a4b5da..2fcad344492f526a98b46b34d2979cd9dd5a872e 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 843b65f46ece168a8694a8a86a974befda12290b..fa2154493cf1537dee269149b1924468a6035325 100644 (file)
@@ -188,7 +188,7 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev)
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        radeon_crtc = to_radeon_crtc(crtc);
                        if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
-                               vrefresh = radeon_crtc->hw_mode.vrefresh;
+                               vrefresh = drm_mode_vrefresh(&radeon_crtc->hw_mode);
                                break;
                        }
                }
index 62c91ed669ce24bdf4f96ea3eb0c7c446e457b1b..dd6606b8e23ca9a3bfd3f7be414b17d01af2aacb 100644 (file)
@@ -476,17 +476,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!dig || !dig->afmt)
                return;
 
-       /* Silent, r600_hdmi_enable will raise WARN for us */
-       if (enable && dig->afmt->enabled)
-               return;
-       if (!enable && !dig->afmt->enabled)
-               return;
-
-       if (!enable && dig->afmt->pin) {
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
-               dig->afmt->pin = NULL;
-       }
-
        /* Older chipsets require setting HDMI and routing manually */
        if (!ASIC_IS_DCE3(rdev)) {
                if (enable)
index 5587603b4a891c1f2cfcf7873dd8aa9e173907df..33d5a4f4eebdc21118b733957a2e1f75230a55cb 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 a3ceef6d9632509b5d1d4cb760539af02a033efe..b21ef69a34ac2a2703f7adad0ee20a15f07d3509 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 63ccb8fa799c209bc82db257d3da0c8fc60ba052..d27e4ccb848c9c60e8a14f71336b790b125d2231 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 c830863bc98aa0cb55e84aedfbbc76606945ee01..4d0f96cc3da4488b0a324058533d26500011293f 100644 (file)
@@ -256,11 +256,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
        u32 ring = RADEON_CS_RING_GFX;
        s32 priority = 0;
 
+       INIT_LIST_HEAD(&p->validated);
+
        if (!cs->num_chunks) {
                return 0;
        }
+
        /* get chunks */
-       INIT_LIST_HEAD(&p->validated);
        p->idx = 0;
        p->ib.sa_bo = NULL;
        p->const_ib.sa_bo = NULL;
@@ -715,6 +717,7 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
        struct radeon_cs_chunk *ib_chunk = p->chunk_ib;
        struct radeon_device *rdev = p->rdev;
        uint32_t header;
+       int ret = 0, i;
 
        if (idx >= ib_chunk->length_dw) {
                DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
@@ -743,14 +746,25 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
                break;
        default:
                DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto dump_ib;
        }
        if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) {
                DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n",
                          pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto dump_ib;
        }
        return 0;
+
+dump_ib:
+       for (i = 0; i < ib_chunk->length_dw; i++) {
+               if (i == idx)
+                       printk("\t0x%08x <---\n", radeon_get_ib_value(p, i));
+               else
+                       printk("\t0x%08x\n", radeon_get_ib_value(p, i));
+       }
+       return ret;
 }
 
 /**
index 6b670b0bc47bb9dca0238ef35dcff1cc2f686c34..3a297037cc176250fff7b1dae4a2566a8fd3c1ca 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 d13d1b5a859f5b4d6aa69adc18cf85a2375398d1..df09ca7c488949896f68ff1d78ad7e152f0fd9a5 100644 (file)
@@ -1030,37 +1030,59 @@ static inline bool radeon_test_signaled(struct radeon_fence *fence)
        return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags);
 }
 
+struct radeon_wait_cb {
+       struct fence_cb base;
+       struct task_struct *task;
+};
+
+static void
+radeon_fence_wait_cb(struct fence *fence, struct fence_cb *cb)
+{
+       struct radeon_wait_cb *wait =
+               container_of(cb, struct radeon_wait_cb, base);
+
+       wake_up_process(wait->task);
+}
+
 static signed long radeon_fence_default_wait(struct fence *f, bool intr,
                                             signed long t)
 {
        struct radeon_fence *fence = to_radeon_fence(f);
        struct radeon_device *rdev = fence->rdev;
-       bool signaled;
+       struct radeon_wait_cb cb;
 
-       fence_enable_sw_signaling(&fence->base);
+       cb.task = current;
 
-       /*
-        * This function has to return -EDEADLK, but cannot hold
-        * exclusive_lock during the wait because some callers
-        * may already hold it. This means checking needs_reset without
-        * lock, and not fiddling with any gpu internals.
-        *
-        * The callback installed with fence_enable_sw_signaling will
-        * run before our wait_event_*timeout call, so we will see
-        * both the signaled fence and the changes to needs_reset.
-        */
+       if (fence_add_callback(f, &cb.base, radeon_fence_wait_cb))
+               return t;
+
+       while (t > 0) {
+               if (intr)
+                       set_current_state(TASK_INTERRUPTIBLE);
+               else
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+
+               /*
+                * radeon_test_signaled must be called after
+                * set_current_state to prevent a race with wake_up_process
+                */
+               if (radeon_test_signaled(fence))
+                       break;
+
+               if (rdev->needs_reset) {
+                       t = -EDEADLK;
+                       break;
+               }
+
+               t = schedule_timeout(t);
+
+               if (t > 0 && intr && signal_pending(current))
+                       t = -ERESTARTSYS;
+       }
+
+       __set_current_state(TASK_RUNNING);
+       fence_remove_callback(f, &cb.base);
 
-       if (intr)
-               t = wait_event_interruptible_timeout(rdev->fence_queue,
-                       ((signaled = radeon_test_signaled(fence)) ||
-                        rdev->needs_reset), t);
-       else
-               t = wait_event_timeout(rdev->fence_queue,
-                       ((signaled = radeon_test_signaled(fence)) ||
-                        rdev->needs_reset), t);
-
-       if (t > 0 && !signaled)
-               return -EDEADLK;
        return t;
 }
 
index 061eaa9c19c7c0d9add6d7fbf84145fc12afb5b7..122eb5693ba191a7458a3496e6bb96b06aee1ac7 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 a69bd441dd2d0cc612b9fa4d9e7711934270e3c5..572b4dbec186a9d59e8066782773c86acdbfa46b 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 43e09942823ec0fbd554800d36585eea91531989..318165d4855c4bf3aa9e4a23bddc38cc25481968 100644 (file)
@@ -173,17 +173,6 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
                else
                        rbo->placements[i].lpfn = 0;
        }
-
-       /*
-        * Use two-ended allocation depending on the buffer size to
-        * improve fragmentation quality.
-        * 512kb was measured as the most optimal number.
-        */
-       if (rbo->tbo.mem.size > 512 * 1024) {
-               for (i = 0; i < c; i++) {
-                       rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN;
-               }
-       }
 }
 
 int radeon_bo_create(struct radeon_device *rdev,
index 9f758d39420dd4affddb42116a09e695a17b6abe..c1ba83a8dd8c9333829aaa5f1384f65c7103d238 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 2456f69efd2310233fac5c75a314a9060abe1a17..8c7872339c2a6f5e94bf601c47ed421e5caee352 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 d02aa1d0f5885408c877056bd4ac1ab0e1ed6f12..b292aca0f342d53856ec3eaf982b71fd8b0a7fa8 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 d81182ad53ec6920b4f7027595882cebf26cdcfc..97a904835759f7876b2b69be104493cf302554a7 100644 (file)
@@ -694,6 +694,10 @@ int rs600_irq_set(struct radeon_device *rdev)
        WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
        if (ASIC_IS_DCE2(rdev))
                WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
+
+       /* posting read */
+       RREG32(R_000040_GEN_INT_CNTL);
+
        return 0;
 }
 
index 73107fe9e46f7de25d1d22b3ad3ba0b28f40c8f0..a7fb2735d4a929b7a20127bce4d7e3c759de2449 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 cbd91d226f3ce232b5933686ad41cae3ace64ebe..99a9835c9f615919c063af1ce0ca0e596aed8c15 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 1ac7bb825a1b3bfecea601d76f8e33c2b8d581ff..fbbe78fbd087ae7c147a43b925f0ac0401c86466 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 3aaa84ae26811fb8c731a89e76b91297b1ff3bf3..1a52522f5da76790dae32fe1a423bd75eaddd1e4 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 7e06657ae58bc1eb2202e7da6c193eb4c8ca862b..7eaaee74a039f36c180629b2233f8455d88b1b6a 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 d395b0bef73b0ce8afffa1d40fb9ea47022ac7fd..8d9b7de2561339b03e2b191e45454eadfd454668 100644 (file)
@@ -74,7 +74,7 @@ static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
        pr_err("    has_type: %d\n", man->has_type);
        pr_err("    use_type: %d\n", man->use_type);
        pr_err("    flags: 0x%08X\n", man->flags);
-       pr_err("    gpu_offset: 0x%08lX\n", man->gpu_offset);
+       pr_err("    gpu_offset: 0x%08llX\n", man->gpu_offset);
        pr_err("    size: %llu\n", man->size);
        pr_err("    available_caching: 0x%08X\n", man->available_caching);
        pr_err("    default_caching: 0x%08X\n", man->default_caching);
index 6c6b655defcf4eac679913e70896810208dfd6ce..e13b9cbc304e9d17a0d5ff55179b2d8b7f93ca7b 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 33176d05db3542903f1c919b59f68cad2da22044..654c8daeb5ab3d0dd84a2ed1d32af633d6955ac9 100644 (file)
@@ -890,7 +890,8 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
        ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use MOB buffer.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_no_reloc;
        }
        bo = &vmw_bo->base;
 
@@ -914,7 +915,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
 
 out_no_reloc:
        vmw_dmabuf_unreference(&vmw_bo);
-       vmw_bo_p = NULL;
+       *vmw_bo_p = NULL;
        return ret;
 }
 
@@ -951,7 +952,8 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
        ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use GMR region.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_no_reloc;
        }
        bo = &vmw_bo->base;
 
@@ -974,7 +976,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
 
 out_no_reloc:
        vmw_dmabuf_unreference(&vmw_bo);
-       vmw_bo_p = NULL;
+       *vmw_bo_p = NULL;
        return ret;
 }
 
@@ -2780,13 +2782,11 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
                                  NULL, arg->command_size, arg->throttle_us,
                                  (void __user *)(unsigned long)arg->fence_rep,
                                  NULL);
-
+       ttm_read_unlock(&dev_priv->reservation_sem);
        if (unlikely(ret != 0))
-               goto out_unlock;
+               return ret;
 
        vmw_kms_cursor_post_execbuf(dev_priv);
 
-out_unlock:
-       ttm_read_unlock(&dev_priv->reservation_sem);
-       return ret;
+       return 0;
 }
index 8725b79e7847d68239a25413c482883e44024704..07cda8cbbddbcb5e6f56127c57dac0e683541fb9 100644 (file)
@@ -2033,23 +2033,17 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
        int i;
        struct drm_mode_config *mode_config = &dev->mode_config;
 
-       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
-       if (unlikely(ret != 0))
-               return ret;
-
        if (!arg->num_outputs) {
                struct drm_vmw_rect def_rect = {0, 0, 800, 600};
                vmw_du_update_layout(dev_priv, 1, &def_rect);
-               goto out_unlock;
+               return 0;
        }
 
        rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect);
        rects = kcalloc(arg->num_outputs, sizeof(struct drm_vmw_rect),
                        GFP_KERNEL);
-       if (unlikely(!rects)) {
-               ret = -ENOMEM;
-               goto out_unlock;
-       }
+       if (unlikely(!rects))
+               return -ENOMEM;
 
        user_rects = (void __user *)(unsigned long)arg->rects;
        ret = copy_from_user(rects, user_rects, rects_size);
@@ -2074,7 +2068,5 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
 
 out_free:
        kfree(rects);
-out_unlock:
-       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 }
index b61d6be97602222d3ae51b39d939d00cf8f5731b..3ddfb3d0b64d266cb95345ccb68c1a991521cc1d 100644 (file)
@@ -459,6 +459,8 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                clkrate = clk_get_rate(di->clk_ipu);
                div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
+               if (div == 0)
+                       div = 1;
                rate = clkrate / div;
 
                error = rate / (sig->mode.pixelclock / 1000);
index db4fb6e1cc5b3ca83d14d3f1e0e52e66fe75979a..56ce8c2b5530db20d851b585fa0c4f88ef81afa6 100644 (file)
@@ -1872,6 +1872,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
@@ -1926,6 +1927,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 #endif
 #if IS_ENABLED(CONFIG_HID_SAITEK)
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
@@ -1957,6 +1959,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
index 46edb4d3ed28efc61582811ea6b5fdeac2a2808a..9c4786759f16f4f397a839214600524b9826254c 100644 (file)
 #define USB_VENDOR_ID_LOGITECH         0x046d
 #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
 #define USB_DEVICE_ID_LOGITECH_T651    0xb00c
+#define USB_DEVICE_ID_LOGITECH_C077    0xc007
 #define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
 #define USB_DEVICE_ID_MS_LK6K          0x00f9
 #define USB_DEVICE_ID_MS_PRESENTER_8K_BT       0x0701
 #define USB_DEVICE_ID_MS_PRESENTER_8K_USB      0x0713
+#define USB_DEVICE_ID_MS_NE7K          0x071d
 #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K      0x0730
 #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500    0x076c
 #define USB_DEVICE_ID_MS_SURFACE_PRO_2   0x0799
 #define USB_VENDOR_ID_SAITEK           0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
 #define USB_DEVICE_ID_SAITEK_PS1000    0x0621
+#define USB_DEVICE_ID_SAITEK_RAT7_OLD  0x0ccb
 #define USB_DEVICE_ID_SAITEK_RAT7      0x0cd7
 #define USB_DEVICE_ID_SAITEK_MMO7      0x0cd0
 
 #define USB_VENDOR_ID_TIVO             0x150a
 #define USB_DEVICE_ID_TIVO_SLIDE_BT    0x1200
 #define USB_DEVICE_ID_TIVO_SLIDE       0x1201
+#define USB_DEVICE_ID_TIVO_SLIDE_PRO   0x1203
 
 #define USB_VENDOR_ID_TOPSEED          0x0766
 #define USB_DEVICE_ID_TOPSEED_CYBERLINK        0x0204
index fbaea6eb882e21afb6cba576279834a099780434..af935eb198c93549867c4e50bb48a997e5cd3f2b 100644 (file)
@@ -264,6 +264,8 @@ static const struct hid_device_id ms_devices[] = {
                .driver_data = MS_ERGONOMY },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
                .driver_data = MS_ERGONOMY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K),
+               .driver_data = MS_ERGONOMY },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
                .driver_data = MS_ERGONOMY | MS_RDESC },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
index 5632c54eadf0206faee31afefc99235763c37e14..a014f21275d8bfada33701b4bef5013f3b81eb2a 100644 (file)
@@ -177,6 +177,8 @@ static int saitek_event(struct hid_device *hdev, struct hid_field *field,
 static const struct hid_device_id saitek_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
                .driver_data = SAITEK_FIX_PS1000 },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD),
+               .driver_data = SAITEK_RELEASE_MODE_RAT7 },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
                .driver_data = SAITEK_RELEASE_MODE_RAT7 },
        { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9),
index 6a58b6c723aa215408051e2b3c967205569a7b94..e54ce1097e2cc57f5049cf852016087a32534c47 100644 (file)
@@ -135,8 +135,9 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
 {
        struct hid_sensor_hub_callbacks_list *callback;
        struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+       unsigned long flags;
 
-       spin_lock(&pdata->dyn_callback_lock);
+       spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
        list_for_each_entry(callback, &pdata->dyn_callback_list, list)
                if (callback->usage_id == usage_id &&
                        (collection_index >=
@@ -145,10 +146,11 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
                                callback->hsdev->end_collection_index)) {
                        *priv = callback->priv;
                        *hsdev = callback->hsdev;
-                       spin_unlock(&pdata->dyn_callback_lock);
+                       spin_unlock_irqrestore(&pdata->dyn_callback_lock,
+                                              flags);
                        return callback->usage_callback;
                }
-       spin_unlock(&pdata->dyn_callback_lock);
+       spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
 
        return NULL;
 }
index 31e9d25611064d0500eba47ea0b710beac31bb0b..1896c019e302934aa13c6f9ac434c51637f450ce 100644 (file)
@@ -804,7 +804,7 @@ union sixaxis_output_report_01 {
 #define DS4_REPORT_0x81_SIZE 7
 #define SIXAXIS_REPORT_0xF2_SIZE 18
 
-static spinlock_t sony_dev_list_lock;
+static DEFINE_SPINLOCK(sony_dev_list_lock);
 static LIST_HEAD(sony_device_list);
 static DEFINE_IDA(sony_device_id_allocator);
 
@@ -1944,6 +1944,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return -ENOMEM;
        }
 
+       spin_lock_init(&sc->lock);
+
        sc->quirks = quirks;
        hid_set_drvdata(hdev, sc);
        sc->hdev = hdev;
@@ -2147,8 +2149,8 @@ static void __exit sony_exit(void)
 {
        dbg_hid("Sony:%s\n", __func__);
 
-       ida_destroy(&sony_device_id_allocator);
        hid_unregister_driver(&sony_driver);
+       ida_destroy(&sony_device_id_allocator);
 }
 module_init(sony_init);
 module_exit(sony_exit);
index d790d8d71f7fc6829f405b7665cc37f0af1bf5a8..d9869692745399b0406dc62b66c1269295ee9835 100644 (file)
@@ -64,6 +64,7 @@ static const struct hid_device_id tivo_devices[] = {
        /* TiVo Slide Bluetooth remote, pairs with a Broadcom dongle */
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, tivo_devices);
index d43e967e75339ec7972e734e284c4356e31a4e38..36053f33d6d93e97009b0d6ba3f4aa5416be8fea 100644 (file)
@@ -370,7 +370,10 @@ static int i2c_hid_hwreset(struct i2c_client *client)
 static void i2c_hid_get_input(struct i2c_hid *ihid)
 {
        int ret, ret_size;
-       int size = ihid->bufsize;
+       int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
+
+       if (size > ihid->bufsize)
+               size = ihid->bufsize;
 
        ret = i2c_master_recv(ihid->client, ihid->inbuf, size);
        if (ret != size) {
@@ -785,7 +788,7 @@ static int i2c_hid_init_irq(struct i2c_client *client)
        dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq);
 
        ret = request_threaded_irq(client->irq, NULL, i2c_hid_irq,
-                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                       IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                        client->name, ihid);
        if (ret < 0) {
                dev_warn(&client->dev,
index 9be99a67bfe2ec9f042e765904913628f8c2b654..a821277534611708973ccf080ad78f4136ef0df5 100644 (file)
@@ -78,6 +78,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS },
index 1a6507999a6534f0b851e209bb702696d1f50e58..bbe32d66e5000157b4d3670c23350ff3fa1a0104 100644 (file)
@@ -551,9 +551,13 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
           (features->type == CINTIQ && !(data[1] & 0x40)))
                return 1;
 
-       if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+       if (wacom->shared) {
                wacom->shared->stylus_in_proximity = true;
 
+               if (wacom->shared->touch_down)
+                       return 1;
+       }
+
        /* in Range while exiting */
        if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
                input_report_key(input, BTN_TOUCH, 0);
@@ -778,6 +782,11 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                        input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
                        input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
                        input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
+                       if ((data[2] & 0x07) | data[4] | data[5] | data[6] | data[7] | data[8] | data[9]) {
+                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+                       } else {
+                               input_report_abs(input, ABS_MISC, 0);
+                       }
                } else if (features->type == CINTIQ_HYBRID) {
                        /*
                         * Do not send hardware buttons under Android. They
@@ -1038,27 +1047,28 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
        int i;
-       int current_num_contacts = 0;
+       int current_num_contacts = data[61];
        int contacts_to_send = 0;
        int num_contacts_left = 4; /* maximum contacts per packet */
        int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
        int y_offset = 2;
+       static int contact_with_no_pen_down_count = 0;
 
        if (wacom->features.type == WACOM_27QHDT) {
                current_num_contacts = data[63];
                num_contacts_left = 10;
                byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET;
                y_offset = 0;
-       } else {
-               current_num_contacts = data[61];
        }
 
        /*
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts)
+       if (current_num_contacts) {
                wacom->num_contacts_left = current_num_contacts;
+               contact_with_no_pen_down_count = 0;
+       }
 
        contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
 
@@ -1091,15 +1101,16 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
                                input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
                                input_report_abs(input, ABS_MT_ORIENTATION, w > h);
                        }
+                       contact_with_no_pen_down_count++;
                }
        }
        input_mt_report_pointer_emulation(input, true);
 
        wacom->num_contacts_left -= contacts_to_send;
-       if (wacom->num_contacts_left <= 0)
+       if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-
-       wacom->shared->touch_down = (wacom->num_contacts_left > 0);
+               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       }
        return 1;
 }
 
@@ -1111,6 +1122,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
        int current_num_contacts = data[2];
        int contacts_to_send = 0;
        int x_offset = 0;
+       static int contact_with_no_pen_down_count = 0;
 
        /* MTTPC does not support Height and Width */
        if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
@@ -1120,8 +1132,10 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts)
+       if (current_num_contacts) {
                wacom->num_contacts_left = current_num_contacts;
+               contact_with_no_pen_down_count = 0;
+       }
 
        /* There are at most 5 contacts per packet */
        contacts_to_send = min(5, wacom->num_contacts_left);
@@ -1142,15 +1156,16 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
                        int y = get_unaligned_le16(&data[offset + x_offset + 9]);
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
                }
        }
        input_mt_report_pointer_emulation(input, true);
 
        wacom->num_contacts_left -= contacts_to_send;
-       if (wacom->num_contacts_left < 0)
+       if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-
-       wacom->shared->touch_down = (wacom->num_contacts_left > 0);
+               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       }
        return 1;
 }
 
@@ -1188,29 +1203,25 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
 {
        unsigned char *data = wacom->data;
        struct input_dev *input = wacom->input;
-       bool prox;
+       bool prox = !wacom->shared->stylus_in_proximity;
        int x = 0, y = 0;
 
        if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
                return 0;
 
-       if (!wacom->shared->stylus_in_proximity) {
-               if (len == WACOM_PKGLEN_TPC1FG) {
-                       prox = data[0] & 0x01;
-                       x = get_unaligned_le16(&data[1]);
-                       y = get_unaligned_le16(&data[3]);
-               } else if (len == WACOM_PKGLEN_TPC1FG_B) {
-                       prox = data[2] & 0x01;
-                       x = get_unaligned_le16(&data[3]);
-                       y = get_unaligned_le16(&data[5]);
-               } else {
-                       prox = data[1] & 0x01;
-                       x = le16_to_cpup((__le16 *)&data[2]);
-                       y = le16_to_cpup((__le16 *)&data[4]);
-               }
-       } else
-               /* force touch out when pen is in prox */
-               prox = 0;
+       if (len == WACOM_PKGLEN_TPC1FG) {
+               prox = prox && (data[0] & 0x01);
+               x = get_unaligned_le16(&data[1]);
+               y = get_unaligned_le16(&data[3]);
+       } else if (len == WACOM_PKGLEN_TPC1FG_B) {
+               prox = prox && (data[2] & 0x01);
+               x = get_unaligned_le16(&data[3]);
+               y = get_unaligned_le16(&data[5]);
+       } else {
+               prox = prox && (data[1] & 0x01);
+               x = le16_to_cpup((__le16 *)&data[2]);
+               y = le16_to_cpup((__le16 *)&data[4]);
+       }
 
        if (prox) {
                input_report_abs(input, ABS_X, x);
@@ -1608,6 +1619,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        struct input_dev *pad_input = wacom->pad_input;
        unsigned char *data = wacom->data;
        int i;
+       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1635,6 +1647,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
                        }
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
                }
        }
 
@@ -1644,11 +1657,12 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
        input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
        input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
        return 1;
 }
 
-static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
+static int wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data, int last_touch_count)
 {
        struct wacom_features *features = &wacom->features;
        struct input_dev *input = wacom->input;
@@ -1656,7 +1670,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
        int slot = input_mt_get_slot_by_key(input, data[0]);
 
        if (slot < 0)
-               return;
+               return 0;
 
        touch = touch && !wacom->shared->stylus_in_proximity;
 
@@ -1688,7 +1702,9 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
                input_report_abs(input, ABS_MT_POSITION_Y, y);
                input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
                input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
+               last_touch_count++;
        }
+       return last_touch_count;
 }
 
 static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
@@ -1713,6 +1729,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
        unsigned char *data = wacom->data;
        int count = data[1] & 0x07;
        int i;
+       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1723,12 +1740,15 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
                int msg_id = data[offset];
 
                if (msg_id >= 2 && msg_id <= 17)
-                       wacom_bpt3_touch_msg(wacom, data + offset);
+                       contact_with_no_pen_down_count = 
+                           wacom_bpt3_touch_msg(wacom, data + offset,
+                                                contact_with_no_pen_down_count);
                else if (msg_id == 128)
                        wacom_bpt3_button_msg(wacom, data + offset);
 
        }
        input_mt_report_pointer_emulation(input, true);
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
        return 1;
 }
@@ -1754,6 +1774,9 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
                return 0;
        }
 
+       if (wacom->shared->touch_down)
+               return 0;
+
        prox = (data[1] & 0x20) == 0x20;
 
        /*
@@ -2725,9 +2748,9 @@ static const struct wacom_features wacom_features_0xF6 =
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x32A =
-       { "Wacom Cintiq 27QHD", 119740, 67520, 2047,
-         63, WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Cintiq 27QHD", 119740, 67520, 2047, 63,
+         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0x32B =
        { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63,
          WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
index bce4e9ff21bff76606484f0a04ad1bf52b1ffee2..6c99ee7bafa3fdf47d6479b7198697ec835a23e8 100644 (file)
@@ -147,6 +147,9 @@ static int ads7828_probe(struct i2c_client *client,
                                                    &ads2830_regmap_config);
        }
 
+       if (IS_ERR(data->regmap))
+               return PTR_ERR(data->regmap);
+
        data->cmd_byte = ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
        if (!diff_input)
                data->cmd_byte |= ADS7828_CMD_SD_SE;
index 5f1ff4cc5c34036ea6284adf9d00fce0ef1fabae..7d7ae97476e2c4cec01765e700e0748bece538bc 100644 (file)
 #include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+
 #include <asm/iosf_mbi.h>
+
 #include "i2c-designware-core.h"
 
 #define SEMAPHORE_TIMEOUT      100
 #define PUNIT_SEMAPHORE                0x7
+#define PUNIT_SEMAPHORE_BIT    BIT(0)
+#define PUNIT_SEMAPHORE_ACQUIRE        BIT(1)
 
 static unsigned long acquired;
 
 static int get_sem(struct device *dev, u32 *sem)
 {
-       u32 reg_val;
+       u32 data;
        int ret;
 
        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE,
-                           &reg_val);
+                               &data);
        if (ret) {
                dev_err(dev, "iosf failed to read punit semaphore\n");
                return ret;
        }
 
-       *sem = reg_val & 0x1;
+       *sem = data & PUNIT_SEMAPHORE_BIT;
 
        return 0;
 }
@@ -52,27 +56,29 @@ static void reset_semaphore(struct device *dev)
                return;
        }
 
-       data = data & 0xfffffffe;
+       data &= ~PUNIT_SEMAPHORE_BIT;
        if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
-                                PUNIT_SEMAPHORE, data))
+                               PUNIT_SEMAPHORE, data))
                dev_err(dev, "iosf failed to reset punit semaphore during write\n");
 }
 
-int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
+static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
 {
-       u32 sem = 0;
+       u32 sem;
        int ret;
        unsigned long start, end;
 
+       might_sleep();
+
        if (!dev || !dev->dev)
                return -ENODEV;
 
-       if (!dev->acquire_lock)
+       if (!dev->release_lock)
                return 0;
 
-       /* host driver writes 0x2 to side band semaphore register */
+       /* host driver writes to side band semaphore register */
        ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
-                                PUNIT_SEMAPHORE, 0x2);
+                               PUNIT_SEMAPHORE, PUNIT_SEMAPHORE_ACQUIRE);
        if (ret) {
                dev_err(dev->dev, "iosf punit semaphore request failed\n");
                return ret;
@@ -81,7 +87,7 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
        /* host driver waits for bit 0 to be set in semaphore register */
        start = jiffies;
        end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
-       while (!time_after(jiffies, end)) {
+       do {
                ret = get_sem(dev->dev, &sem);
                if (!ret && sem) {
                        acquired = jiffies;
@@ -91,14 +97,14 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
                }
 
                usleep_range(1000, 2000);
-       }
+       } while (time_before(jiffies, end));
 
        dev_err(dev->dev, "punit semaphore timed out, resetting\n");
        reset_semaphore(dev->dev);
 
        ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
-               PUNIT_SEMAPHORE, &sem);
-       if (!ret)
+                               PUNIT_SEMAPHORE, &sem);
+       if (ret)
                dev_err(dev->dev, "iosf failed to read punit semaphore\n");
        else
                dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
@@ -107,9 +113,8 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
 
        return -ETIMEDOUT;
 }
-EXPORT_SYMBOL(baytrail_i2c_acquire);
 
-void baytrail_i2c_release(struct dw_i2c_dev *dev)
+static void baytrail_i2c_release(struct dw_i2c_dev *dev)
 {
        if (!dev || !dev->dev)
                return;
@@ -121,7 +126,6 @@ void baytrail_i2c_release(struct dw_i2c_dev *dev)
        dev_dbg(dev->dev, "punit semaphore held for %ums\n",
                jiffies_to_msecs(jiffies - acquired));
 }
-EXPORT_SYMBOL(baytrail_i2c_release);
 
 int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
 {
@@ -137,7 +141,6 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
                return 0;
 
        status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
-
        if (ACPI_FAILURE(status))
                return 0;
 
@@ -153,7 +156,6 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
 
        return 0;
 }
-EXPORT_SYMBOL(i2c_dw_eval_lock_support);
 
 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
 MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
index 210cf4874cb7ea2415df5fb3e1d30ec8065de5d4..edf274cabe817208f0c4b3fceb98bca95f2671f4 100644 (file)
@@ -679,9 +679,6 @@ static int i2c_device_remove(struct device *dev)
                status = driver->remove(client);
        }
 
-       if (dev->of_node)
-               irq_dispose_mapping(client->irq);
-
        dev_pm_domain_detach(&client->dev, true);
        return status;
 }
index 1793aea4a7d2c58192f6023d43e90c10daedbb52..6eb738ca6d2f353717aac1e63bade383f763afa5 100644 (file)
@@ -1793,11 +1793,11 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN,
                                         IDETAPE_DSC_RW_MAX);
        printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
-               "%lums tDSC%s\n",
+               "%ums tDSC%s\n",
                drive->name, tape->name, *(u16 *)&tape->caps[14],
                (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
                tape->buffer_size / 1024,
-               tape->best_dsc_rw_freq * 1000 / HZ,
+               jiffies_to_msecs(tape->best_dsc_rw_freq),
                (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
 
        ide_proc_register_driver(drive, tape->driver);
index 1096da327130526080139e628fdd0a0130d32861..75c6d2103e07adad3b11919687e81f8dd7a8fca3 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 066d0c04072c69943fa21313fb47f06c72fedcea..75567fd457dcc4b9bd7c147fdc4cb229cdbaf0c4 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 567de269cc00650191541a98ac8d5818d0ea8661..1a6379525fa47e73497b17866be4276fc88c8065 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 202daf889be276315d24575b1301349f295fe4c8..46379b1fb25b59b10018a121b2cc8dc78082d4a6 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 ff61ae55dd3ff8ac73c0925c0b88fa6a75a1083d..8a0eb4a04fb55b9cb2436db5b16f678f654b8a26 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 51672256072bc8db2778e6c60982f320c680f3d4..b96c636470ef504e3b7f3d5612602bcc76a3a3a0 100644 (file)
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
        }
 
-/* LSB is in nV to eliminate floating point */
-static const u32 rates_to_lsb[] = {1000000, 250000, 62500, 15625};
-
-/*
- *  scales calculated as:
- *  rates_to_lsb[sample_rate] / (1 << pga);
- *  pga is 1 for 0, 2
- */
-
 static const int mcp3422_scales[4][4] = {
-       { 1000000, 250000, 62500, 15625 },
-       { 500000 , 125000, 31250, 7812 },
-       { 250000 , 62500 , 15625, 3906 },
-       { 125000 , 31250 , 7812 , 1953 } };
+       { 1000000, 500000, 250000, 125000 },
+       { 250000 , 125000, 62500 , 31250  },
+       { 62500  , 31250 , 15625 , 7812   },
+       { 15625  , 7812  , 3906  , 1953   } };
 
 /* Constant msleep times for data acquisitions */
 static const int mcp3422_read_times[4] = {
index b9666f2f5e514f8d3a66a0a192b190bcbd2a44d5..fabd24edc2a1d07534d2a67e9a1c8e78ef353cae 100644 (file)
@@ -296,7 +296,8 @@ static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
        if (iadc->poll_eoc) {
                ret = iadc_poll_wait_eoc(iadc, wait);
        } else {
-               ret = wait_for_completion_timeout(&iadc->complete, wait);
+               ret = wait_for_completion_timeout(&iadc->complete,
+                       usecs_to_jiffies(wait));
                if (!ret)
                        ret = -ETIMEDOUT;
                else
index 2e5cc4409f78884e82f309c729febabe3ff7f982..a0e7161f040c91daca74a469d27ff641be9ea915 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 8ec353c01d98e02e7074df9d4d295ec19f772f09..e63b8e76d4c3d54edc25d23561f28a11afeb05e7 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 52d70435f5a11c55ed186003c70bce311002f918..55a90082a29bd4846aaea896f8c7f847d96fcb45 100644 (file)
@@ -640,6 +640,7 @@ static int ssp_remove(struct spi_device *spi)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int ssp_suspend(struct device *dev)
 {
        int ret;
@@ -688,6 +689,7 @@ static int ssp_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops ssp_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
index f57562aa396f44462a9fdc822741d09bf37531f4..15c73e20272d874655e544366e2a8d6f1c24912a 100644 (file)
@@ -322,7 +322,7 @@ static int ad5686_probe(struct spi_device *spi)
        st = iio_priv(indio_dev);
        spi_set_drvdata(spi, indio_dev);
 
-       st->reg = devm_regulator_get(&spi->dev, "vcc");
+       st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
        if (!IS_ERR(st->reg)) {
                ret = regulator_enable(st->reg);
                if (ret)
index 60451b32824212a039b8ac9358751faa1af12819..ccf3ea7e1afa8ca1848937b9a8b92e1f2cefc8be 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 623c145d8a97241bd0c2e284d9bb273dfcfb72da..7d79a1ac5f5f09ba332fee3ebb94c486280ce024 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/wait.h>
 #include <linux/bitops.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 
 #define DHT11_DATA_VALID_TIME  2000000000  /* 2s in ns */
 
-#define DHT11_EDGES_PREAMBLE 4
+#define DHT11_EDGES_PREAMBLE 2
 #define DHT11_BITS_PER_READ 40
+/*
+ * Note that when reading the sensor actually 84 edges are detected, but
+ * since the last edge is not significant, we only store 83:
+ */
 #define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1)
 
 /* Data transmission timing (nano seconds) */
@@ -57,6 +62,7 @@ struct dht11 {
        int                             irq;
 
        struct completion               completion;
+       struct mutex                    lock;
 
        s64                             timestamp;
        int                             temperature;
@@ -88,7 +94,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
        unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
 
        /* Calculate timestamp resolution */
-       for (i = 0; i < dht11->num_edges; ++i) {
+       for (i = 1; i < dht11->num_edges; ++i) {
                t = dht11->edges[i].ts - dht11->edges[i-1].ts;
                if (t > 0 && t < timeres)
                        timeres = t;
@@ -138,6 +144,27 @@ static int dht11_decode(struct dht11 *dht11, int offset)
        return 0;
 }
 
+/*
+ * IRQ handler called on GPIO edges
+ */
+static irqreturn_t dht11_handle_irq(int irq, void *data)
+{
+       struct iio_dev *iio = data;
+       struct dht11 *dht11 = iio_priv(iio);
+
+       /* TODO: Consider making the handler safe for IRQ sharing */
+       if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
+               dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
+               dht11->edges[dht11->num_edges++].value =
+                                               gpio_get_value(dht11->gpio);
+
+               if (dht11->num_edges >= DHT11_EDGES_PER_READ)
+                       complete(&dht11->completion);
+       }
+
+       return IRQ_HANDLED;
+}
+
 static int dht11_read_raw(struct iio_dev *iio_dev,
                        const struct iio_chan_spec *chan,
                        int *val, int *val2, long m)
@@ -145,6 +172,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
        struct dht11 *dht11 = iio_priv(iio_dev);
        int ret;
 
+       mutex_lock(&dht11->lock);
        if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
                reinit_completion(&dht11->completion);
 
@@ -157,8 +185,17 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                if (ret)
                        goto err;
 
+               ret = request_irq(dht11->irq, dht11_handle_irq,
+                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                 iio_dev->name, iio_dev);
+               if (ret)
+                       goto err;
+
                ret = wait_for_completion_killable_timeout(&dht11->completion,
                                                                 HZ);
+
+               free_irq(dht11->irq, iio_dev);
+
                if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
                        dev_err(&iio_dev->dev,
                                        "Only %d signal edges detected\n",
@@ -185,6 +222,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                ret = -EINVAL;
 err:
        dht11->num_edges = -1;
+       mutex_unlock(&dht11->lock);
        return ret;
 }
 
@@ -193,27 +231,6 @@ static const struct iio_info dht11_iio_info = {
        .read_raw               = dht11_read_raw,
 };
 
-/*
- * IRQ handler called on GPIO edges
-*/
-static irqreturn_t dht11_handle_irq(int irq, void *data)
-{
-       struct iio_dev *iio = data;
-       struct dht11 *dht11 = iio_priv(iio);
-
-       /* TODO: Consider making the handler safe for IRQ sharing */
-       if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
-               dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
-               dht11->edges[dht11->num_edges++].value =
-                                               gpio_get_value(dht11->gpio);
-
-               if (dht11->num_edges >= DHT11_EDGES_PER_READ)
-                       complete(&dht11->completion);
-       }
-
-       return IRQ_HANDLED;
-}
-
 static const struct iio_chan_spec dht11_chan_spec[] = {
        { .type = IIO_TEMP,
                .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), },
@@ -256,11 +273,6 @@ static int dht11_probe(struct platform_device *pdev)
                dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);
                return -EINVAL;
        }
-       ret = devm_request_irq(dev, dht11->irq, dht11_handle_irq,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               pdev->name, iio);
-       if (ret)
-               return ret;
 
        dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
        dht11->num_edges = -1;
@@ -268,6 +280,7 @@ static int dht11_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, iio);
 
        init_completion(&dht11->completion);
+       mutex_init(&dht11->lock);
        iio->name = pdev->name;
        iio->dev.parent = &pdev->dev;
        iio->info = &dht11_iio_info;
index b54164677b898d5c9e5b4b9983fe61271f3c80b5..fa3b809aff5efd425ce96031aec1c066b644feb2 100644 (file)
@@ -45,12 +45,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan, int *val,
                           int *val2, long mask)
 {
-       struct i2c_client *client = iio_priv(indio_dev);
+       struct i2c_client **client = iio_priv(indio_dev);
        int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = i2c_smbus_read_word_data(client,
+               ret = i2c_smbus_read_word_data(*client,
                                               chan->type == IIO_TEMP ?
                                               SI7020CMD_TEMP_HOLD :
                                               SI7020CMD_RH_HOLD);
@@ -126,7 +126,7 @@ static int si7020_probe(struct i2c_client *client,
        /* Wait the maximum power-up time after software reset. */
        msleep(15);
 
-       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client));
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
        if (!indio_dev)
                return -ENOMEM;
 
index b70873de04ea50a7cb73f34835f15c43ceff9eb1..fa795dcd5f75ec0a1e8de143bc0122ef36bf9409 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/debugfs.h>
+#include <linux/bitops.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -414,7 +415,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
                mutex_unlock(&indio_dev->mlock);
                if (ret)
                        return ret;
-               val16 = ((val16 & 0xFFF) << 4) >> 4;
+               val16 = sign_extend32(val16, 11);
                *val = val16;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_OFFSET:
index e0017c22bb9c6ce3b4f4f9c753a8ce1364621b19..f53e9a803a0e1ec1589a5b0ad25d7aa1f8d54e70 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 f73e60b7a79611b8825bfe90ea3ba5a5e1b253b1..ef76afe2643cb0bebe512124ca8c9326e09229c2 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 0cd306a72a6e347391ea97d7a02d05e54b6c64ab..ba27e277511fc52585f8fa25fd20d49bca61be96 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 5cc3692acf377664dbf255a698bb5e64606fe864..b3a36376c719317006cf8b9d30e1369f8b6af8fb 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 aaba9d3d980ee623ad6b78111a9c9708198b23e0..4df97f650e448e80053e037fed6d5e208493c687 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 a4b397048f71f9fe2e22be46f45fca0fb06cb8ff..a99692ba91bc75fb3186f69f2d55bfc9efd6652c 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 ae68c64bdad3ef7480d15da5d1187c1fd4f7ba4f..a224afd6380c84eff7c76996c7c38eb621493140 100644 (file)
@@ -73,6 +73,7 @@ config CM36651
 config GP2AP020A00F
        tristate "Sharp GP2AP020A00F Proximity/ALS sensor"
        depends on I2C
+       select REGMAP_I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select IRQ_WORK
@@ -126,6 +127,7 @@ config HID_SENSOR_PROX
 config JSA1212
        tristate "JSA1212 ALS and proximity sensor driver"
        depends on I2C
+       select REGMAP_I2C
        help
         Say Y here if you want to build a IIO driver for JSA1212
         proximity & ALS sensor device.
index 4c7a4c52dd06bf7be91a6a1b1d9d56ff7984650c..a5d6de72c523bab274f003cc8431ce05b29630c7 100644 (file)
@@ -18,6 +18,8 @@ config AK8975
 
 config AK09911
        tristate "Asahi Kasei AK09911 3-axis Compass"
+       depends on I2C
+       depends on GPIOLIB
        select AK8975
        help
          Deprecated: AK09911 is now supported by AK8975 driver.
index 74dff4e4a11acdda1ec44ec6eaec75ef4d0543e4..89fca3a7075039b9b9a0de5514c1b96758d4593b 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 aec7a6aa2951db47bc6b5be969a29d1867688b23..8c014b5dab4c82ff805a744c89655555a56094fc 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 c7619716c31dd92cb5ddad4f77d98528392698b5..59040265e3614a23fc8508e88dd5b2138e7107e8 100644 (file)
@@ -64,6 +64,14 @@ enum {
 #define GUID_TBL_BLK_NUM_ENTRIES 8
 #define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES)
 
+/* Counters should be saturate once they reach their maximum value */
+#define ASSIGN_32BIT_COUNTER(counter, value) do {\
+       if ((value) > U32_MAX)                   \
+               counter = cpu_to_be32(U32_MAX); \
+       else                                     \
+               counter = cpu_to_be32(value);    \
+} while (0)
+
 struct mlx4_mad_rcv_buf {
        struct ib_grh grh;
        u8 payload[256];
@@ -806,10 +814,14 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
 static void edit_counter(struct mlx4_counter *cnt,
                                        struct ib_pma_portcounters *pma_cnt)
 {
-       pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2));
-       pma_cnt->port_rcv_data  = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2));
-       pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames));
-       pma_cnt->port_rcv_packets  = cpu_to_be32(be64_to_cpu(cnt->rx_frames));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
+                            (be64_to_cpu(cnt->tx_bytes) >> 2));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
+                            (be64_to_cpu(cnt->rx_bytes) >> 2));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
+                            be64_to_cpu(cnt->tx_frames));
+       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
+                            be64_to_cpu(cnt->rx_frames));
 }
 
 static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
index ac6e2b710ea6fef928271869f0e170f2bbdb158d..b972c0b41799b51e2f554c1abc703d78e0c4636e 100644 (file)
@@ -2697,8 +2697,12 @@ static void handle_bonded_port_state_event(struct work_struct *work)
        spin_lock_bh(&ibdev->iboe.lock);
        for (i = 0; i < MLX4_MAX_PORTS; ++i) {
                struct net_device *curr_netdev = ibdev->iboe.netdevs[i];
+               enum ib_port_state curr_port_state;
 
-               enum ib_port_state curr_port_state =
+               if (!curr_netdev)
+                       continue;
+
+               curr_port_state =
                        (netif_running(curr_netdev) &&
                         netif_carrier_ok(curr_netdev)) ?
                        IB_PORT_ACTIVE : IB_PORT_DOWN;
index 8ff612d160b07ec61b7084d668f04468ee116b36..563932500ff1bbfbf83c84c06b4f64205450045b 100644 (file)
@@ -411,9 +411,9 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
 
        input_set_drvdata(input, keypad);
 
-       error = request_threaded_irq(irq, NULL,
-                       tc3589x_keypad_irq, plat->irqtype,
-                       "tc3589x-keypad", keypad);
+       error = request_threaded_irq(irq, NULL, tc3589x_keypad_irq,
+                                    plat->irqtype | IRQF_ONESHOT,
+                                    "tc3589x-keypad", keypad);
        if (error < 0) {
                dev_err(&pdev->dev,
                                "Could not allocate irq %d,error %d\n",
index 59d4dcddf6de0cf4d1c5384c977a36c319d66389..98228773a1118bfd448ec0143c4b572a534af499 100644 (file)
@@ -187,6 +187,7 @@ static int mma8450_probe(struct i2c_client *c,
        idev->private           = m;
        idev->input->name       = MMA8450_DRV_NAME;
        idev->input->id.bustype = BUS_I2C;
+       idev->input->dev.parent = &c->dev;
        idev->poll              = mma8450_poll;
        idev->poll_interval     = POLL_INTERVAL;
        idev->poll_interval_max = POLL_INTERVAL_MAX;
index d28726a0ef858e252948d2e5f2fd009bfd6c5506..27bcdbc950c9fc2df9067504cfe055bf379eee78 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 77e9d70a986bc049ecc48650bff28d34d97443d8..1e2291c378feb8856b319dc5c2e6492360de1ada 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/input/mt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 #include "cyapa.h"
 
 
index ddf5393a118098fc87337d34e3808c0cfc28ce95..5b611dd71e790660fa1492dab505499222390d02 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <linux/slab.h>
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 #include <linux/crc-itu-t.h>
 #include "cyapa.h"
 
@@ -1926,7 +1926,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
                                electrodes_tx = cyapa->electrodes_x;
                        max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) &
                                                ~7u) * electrodes_tx;
-               } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+               } else {
                        offset = 2;
                        max_element_cnt = cyapa->electrodes_x +
                                                cyapa->electrodes_y;
index 757f78a94aeccb1be6b80819f75752a09e705bf6..23d259416f2f4d90d40a04271e98e6f8acca3966 100644 (file)
@@ -67,9 +67,6 @@ static void focaltech_reset(struct psmouse *psmouse)
 
 #define FOC_MAX_FINGERS 5
 
-#define FOC_MAX_X 2431
-#define FOC_MAX_Y 1663
-
 /*
  * Current state of a single finger on the touchpad.
  */
@@ -129,9 +126,17 @@ static void focaltech_report_state(struct psmouse *psmouse)
                input_mt_slot(dev, i);
                input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
                if (active) {
-                       input_report_abs(dev, ABS_MT_POSITION_X, finger->x);
+                       unsigned int clamped_x, clamped_y;
+                       /*
+                        * The touchpad might report invalid data, so we clamp
+                        * the resulting values so that we do not confuse
+                        * userspace.
+                        */
+                       clamped_x = clamp(finger->x, 0U, priv->x_max);
+                       clamped_y = clamp(finger->y, 0U, priv->y_max);
+                       input_report_abs(dev, ABS_MT_POSITION_X, clamped_x);
                        input_report_abs(dev, ABS_MT_POSITION_Y,
-                                        FOC_MAX_Y - finger->y);
+                                        priv->y_max - clamped_y);
                }
        }
        input_mt_report_pointer_emulation(dev, true);
@@ -180,16 +185,6 @@ static void focaltech_process_abs_packet(struct psmouse *psmouse,
 
        state->pressed = (packet[0] >> 4) & 1;
 
-       /*
-        * packet[5] contains some kind of tool size in the most
-        * significant nibble. 0xff is a special value (latching) that
-        * signals a large contact area.
-        */
-       if (packet[5] == 0xff) {
-               state->fingers[finger].valid = false;
-               return;
-       }
-
        state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
        state->fingers[finger].y = (packet[3] << 8) | packet[4];
        state->fingers[finger].valid = true;
@@ -381,6 +376,23 @@ static int focaltech_read_size(struct psmouse *psmouse)
 
        return 0;
 }
+
+void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+       /* not supported yet */
+}
+
+static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+       /* not supported yet */
+}
+
+static void focaltech_set_scale(struct psmouse *psmouse,
+                               enum psmouse_scale scale)
+{
+       /* not supported yet */
+}
+
 int focaltech_init(struct psmouse *psmouse)
 {
        struct focaltech_data *priv;
@@ -415,6 +427,14 @@ int focaltech_init(struct psmouse *psmouse)
        psmouse->cleanup = focaltech_reset;
        /* resync is not supported yet */
        psmouse->resync_time = 0;
+       /*
+        * rate/resolution/scale changes are not supported yet, and
+        * the generic implementations of these functions seem to
+        * confuse some touchpads
+        */
+       psmouse->set_resolution = focaltech_set_resolution;
+       psmouse->set_rate = focaltech_set_rate;
+       psmouse->set_scale = focaltech_set_scale;
 
        return 0;
 
index 4ccd01d7a48de9639a637db4a757c2c09c6c6836..8bc61237bc1b1c95d43b0d7e3d11e90275aa8d4a 100644 (file)
@@ -453,6 +453,17 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
        psmouse->rate = r;
 }
 
+/*
+ * Here we set the mouse scaling.
+ */
+
+static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale)
+{
+       ps2_command(&psmouse->ps2dev, NULL,
+                   scale == PSMOUSE_SCALE21 ? PSMOUSE_CMD_SETSCALE21 :
+                                              PSMOUSE_CMD_SETSCALE11);
+}
+
 /*
  * psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
  */
@@ -689,6 +700,7 @@ static void psmouse_apply_defaults(struct psmouse *psmouse)
 
        psmouse->set_rate = psmouse_set_rate;
        psmouse->set_resolution = psmouse_set_resolution;
+       psmouse->set_scale = psmouse_set_scale;
        psmouse->poll = psmouse_poll;
        psmouse->protocol_handler = psmouse_process_byte;
        psmouse->pktsize = 3;
@@ -1160,7 +1172,7 @@ static void psmouse_initialize(struct psmouse *psmouse)
        if (psmouse_max_proto != PSMOUSE_PS2) {
                psmouse->set_rate(psmouse, psmouse->rate);
                psmouse->set_resolution(psmouse, psmouse->resolution);
-               ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+               psmouse->set_scale(psmouse, PSMOUSE_SCALE11);
        }
 }
 
index c2ff137ecbdb636ba75da72fe14c61a73ec59a5e..d02e1bdc9ae4934d56e5290f8adedcb3a2297566 100644 (file)
@@ -36,6 +36,11 @@ typedef enum {
        PSMOUSE_FULL_PACKET
 } psmouse_ret_t;
 
+enum psmouse_scale {
+       PSMOUSE_SCALE11,
+       PSMOUSE_SCALE21
+};
+
 struct psmouse {
        void *private;
        struct input_dev *dev;
@@ -67,6 +72,7 @@ struct psmouse {
        psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
        void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
        void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution);
+       void (*set_scale)(struct psmouse *psmouse, enum psmouse_scale scale);
 
        int (*reconnect)(struct psmouse *psmouse);
        void (*disconnect)(struct psmouse *psmouse);
index f2cceb6493a0aea304c838043735ac3889041438..3b06c8a360b661f02ed3aa826e5a996b93e5b358 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 aedc3299b14e2b753c1e9d51da95b0953ea081cb..ee4bd0d12b26fa2770445a381134b62124be6741 100644 (file)
@@ -22,6 +22,7 @@
 #define SYN_QUE_EXT_CAPAB_0C           0x0c
 #define SYN_QUE_EXT_MAX_COORDS         0x0d
 #define SYN_QUE_EXT_MIN_COORDS         0x0f
+#define SYN_QUE_MEXT_CAPAB_10          0x10
 
 /* synatics modes */
 #define SYN_BIT_ABSOLUTE_MODE          (1 << 7)
@@ -53,6 +54,7 @@
 #define SYN_EXT_CAP_REQUESTS(c)                (((c) & 0x700000) >> 20)
 #define SYN_CAP_MULTI_BUTTON_NO(ec)    (((ec) & 0x00f000) >> 12)
 #define SYN_CAP_PRODUCT_ID(ec)         (((ec) & 0xff0000) >> 16)
+#define SYN_MEXT_CAP_BIT(m)            ((m) & (1 << 1))
 
 /*
  * The following describes response for the 0x0c query.
 #define SYN_CAP_REDUCED_FILTERING(ex0c)        ((ex0c) & 0x000400)
 #define SYN_CAP_IMAGE_SENSOR(ex0c)     ((ex0c) & 0x000800)
 
+/*
+ * The following descibes response for the 0x10 query.
+ *
+ * byte        mask    name                    meaning
+ * ----        ----    -------                 ------------
+ * 1   0x01    ext buttons are stick   buttons exported in the extended
+ *                                     capability are actually meant to be used
+ *                                     by the tracktick (pass-through).
+ * 1   0x02    SecurePad               the touchpad is a SecurePad, so it
+ *                                     contains a built-in fingerprint reader.
+ * 1   0xe0    more ext count          how many more extented queries are
+ *                                     available after this one.
+ * 2   0xff    SecurePad width         the width of the SecurePad fingerprint
+ *                                     reader.
+ * 3   0xff    SecurePad height        the height of the SecurePad fingerprint
+ *                                     reader.
+ */
+#define SYN_CAP_EXT_BUTTONS_STICK(ex10)        ((ex10) & 0x010000)
+#define SYN_CAP_SECUREPAD(ex10)                ((ex10) & 0x020000)
+
+#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01))
+#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02))
+#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04))
+
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)           ((m) & (1 << 7))
 #define SYN_MODE_RATE(m)               ((m) & (1 << 6))
@@ -143,6 +169,7 @@ struct synaptics_data {
        unsigned long int capabilities;         /* Capabilities */
        unsigned long int ext_cap;              /* Extended Capabilities */
        unsigned long int ext_cap_0c;           /* Ext Caps from 0x0c query */
+       unsigned long int ext_cap_10;           /* Ext Caps from 0x10 query */
        unsigned long int identity;             /* Identification */
        unsigned int x_res, y_res;              /* X/Y resolution in units/mm */
        unsigned int x_max, y_max;              /* Max coordinates (from FW) */
@@ -156,6 +183,7 @@ struct synaptics_data {
        bool disable_gesture;                   /* disable gestures */
 
        struct serio *pt_port;                  /* Pass-through serio port */
+       unsigned char pt_buttons;               /* Pass-through buttons */
 
        /*
         * Last received Advanced Gesture Mode (AGM) packet. An AGM packet
index 58917525126e86fd06cb632b2cbb3f558b0a2f83..6261fd6d7c3c4ddcb758b6796b0ba6ca0c222c99 100644 (file)
@@ -943,6 +943,7 @@ config TOUCHSCREEN_SUN4I
        tristate "Allwinner sun4i resistive touchscreen controller support"
        depends on ARCH_SUNXI || COMPILE_TEST
        depends on HWMON
+       depends on THERMAL || !THERMAL_OF
        help
          This selects support for the resistive touchscreen controller
          found on Allwinner sunxi SoCs.
index baa0d9786f506bfeff064459e1f2277cd2506b6b..1ae4e547b419b909a9748b54cc6b973d31ff0221 100644 (file)
@@ -23,6 +23,7 @@ config IOMMU_IO_PGTABLE
 config IOMMU_IO_PGTABLE_LPAE
        bool "ARMv7/v8 Long Descriptor Format"
        select IOMMU_IO_PGTABLE
+       depends on ARM || ARM64 || COMPILE_TEST
        help
          Enable support for the ARM long descriptor pagetable format.
          This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page
@@ -63,6 +64,7 @@ config MSM_IOMMU
        bool "MSM IOMMU Support"
        depends on ARM
        depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST
+       depends on BROKEN
        select IOMMU_API
        help
          Support for the IOMMUs found on certain Qualcomm SOCs.
index fc13dd56953e1eb2cb25107ef017336546b733a7..a3adde6519f0a24b7150f8e69ceabed534ceaa38 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 7ce52737c7a129c825397733041d945cd05761bf..dc14fec4ede123b0af6564f641d81dcfcb958b25 100644 (file)
@@ -1186,8 +1186,15 @@ static const struct iommu_ops exynos_iommu_ops = {
 
 static int __init exynos_iommu_init(void)
 {
+       struct device_node *np;
        int ret;
 
+       np = of_find_matching_node(NULL, sysmmu_of_match);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
+
        lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table",
                                LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL);
        if (!lv2table_kmem_cache) {
index ae4c1a854e57896fc64e33668369bebc23f70945..2d1e05bdbb53f5901035294a71c65231b004a338 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 5a500edf00cc146805d0a346525e0b9169c816c5..b610a8dee23820573b6362472b4ab5ec31c4003f 100644 (file)
@@ -56,7 +56,8 @@
        ((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1))             \
          * (d)->bits_per_level) + (d)->pg_shift)
 
-#define ARM_LPAE_PAGES_PER_PGD(d)      ((d)->pgd_size >> (d)->pg_shift)
+#define ARM_LPAE_PAGES_PER_PGD(d)                                      \
+       DIV_ROUND_UP((d)->pgd_size, 1UL << (d)->pg_shift)
 
 /*
  * Calculate the index at level l used to map virtual address a using the
@@ -66,7 +67,7 @@
        ((l) == ARM_LPAE_START_LVL(d) ? ilog2(ARM_LPAE_PAGES_PER_PGD(d)) : 0)
 
 #define ARM_LPAE_LVL_IDX(a,l,d)                                                \
-       (((a) >> ARM_LPAE_LVL_SHIFT(l,d)) &                             \
+       (((u64)(a) >> ARM_LPAE_LVL_SHIFT(l,d)) &                        \
         ((1 << ((d)->bits_per_level + ARM_LPAE_PGD_IDX(l,d))) - 1))
 
 /* Calculate the block/page mapping size at level l for pagetable in d. */
index 10186cac7716e246ea8b8a6e915bf07970670f5b..bc39bdf7b99bf170d793965e28777d3c7a279537 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 f59f857b702e8e3f65080edd43b743a54091170f..a4ba851825c235b5bfa7ab93a8256adfca160ca7 100644 (file)
@@ -1376,6 +1376,13 @@ static int __init omap_iommu_init(void)
        struct kmem_cache *p;
        const unsigned long flags = SLAB_HWCACHE_ALIGN;
        size_t align = 1 << 10; /* L2 pagetable alignement */
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, omap_iommu_of_match);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
 
        p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
                              iopte_cachep_ctor);
index 6a8b1ec4a48a1f1100bc0f9f301fc658758a35ca..9f74fddcd304f76bd8a9d546f1d2caf74e7dc588 100644 (file)
@@ -1015,8 +1015,15 @@ static struct platform_driver rk_iommu_driver = {
 
 static int __init rk_iommu_init(void)
 {
+       struct device_node *np;
        int ret;
 
+       np = of_find_matching_node(NULL, rk_iommu_dt_ids);
+       if (!np)
+               return 0;
+
+       of_node_put(np);
+
        ret = bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
        if (ret)
                return ret;
index 463c235acbdcdc1758329205e3c79e380b5fa7a6..4387dae14e453a949bb297ec1a74a59e400a3089 100644 (file)
@@ -69,6 +69,7 @@ static void __iomem *per_cpu_int_base;
 static void __iomem *main_int_base;
 static struct irq_domain *armada_370_xp_mpic_domain;
 static u32 doorbell_mask_reg;
+static int parent_irq;
 #ifdef CONFIG_PCI_MSI
 static struct irq_domain *armada_370_xp_msi_domain;
 static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
@@ -356,6 +357,7 @@ static int armada_xp_mpic_secondary_init(struct notifier_block *nfb,
 {
        if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
                armada_xp_mpic_smp_cpu_init();
+
        return NOTIFY_OK;
 }
 
@@ -364,6 +366,20 @@ static struct notifier_block armada_370_xp_mpic_cpu_notifier = {
        .priority = 100,
 };
 
+static int mpic_cascaded_secondary_init(struct notifier_block *nfb,
+                                       unsigned long action, void *hcpu)
+{
+       if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
+               enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block mpic_cascaded_cpu_notifier = {
+       .notifier_call = mpic_cascaded_secondary_init,
+       .priority = 100,
+};
+
 #endif /* CONFIG_SMP */
 
 static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
@@ -539,7 +555,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
                                             struct device_node *parent)
 {
        struct resource main_int_res, per_cpu_int_res;
-       int parent_irq, nr_irqs, i;
+       int nr_irqs, i;
        u32 control;
 
        BUG_ON(of_address_to_resource(node, 0, &main_int_res));
@@ -587,6 +603,9 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
                register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier);
 #endif
        } else {
+#ifdef CONFIG_SMP
+               register_cpu_notifier(&mpic_cascaded_cpu_notifier);
+#endif
                irq_set_chained_handler(parent_irq,
                                        armada_370_xp_mpic_handle_cascade_irq);
        }
index d8996bdf0f61e95e45ee670e44e565d045fb9535..9687f8afebffbb865256ba6677663e6c76702aa1 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 1c6dea2fbc34ce2d7b00007250111166315d8b78..fd8850def1b86a3310e376c821c3aaf33153f1cc 100644 (file)
@@ -466,7 +466,7 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
                tlist |= 1 << (mpidr & 0xf);
 
                cpu = cpumask_next(cpu, mask);
-               if (cpu == nr_cpu_ids)
+               if (cpu >= nr_cpu_ids)
                        goto out;
 
                mpidr = cpu_logical_map(cpu);
index 4634cf7d0ec379d5578319d45194cb18c9997510..471e1cdc193365dce99dcb53e3c8b21a388e0faa 100644 (file)
@@ -154,23 +154,25 @@ static inline unsigned int gic_irq(struct irq_data *d)
 static void gic_mask_irq(struct irq_data *d)
 {
        u32 mask = 1 << (gic_irq(d) % 32);
+       unsigned long flags;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
        if (gic_arch_extn.irq_mask)
                gic_arch_extn.irq_mask(d);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 static void gic_unmask_irq(struct irq_data *d)
 {
        u32 mask = 1 << (gic_irq(d) % 32);
+       unsigned long flags;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        if (gic_arch_extn.irq_unmask)
                gic_arch_extn.irq_unmask(d);
        writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 static void gic_eoi_irq(struct irq_data *d)
@@ -188,6 +190,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 {
        void __iomem *base = gic_dist_base(d);
        unsigned int gicirq = gic_irq(d);
+       unsigned long flags;
        int ret;
 
        /* Interrupt configuration for SGIs can't be changed */
@@ -199,14 +202,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
                            type != IRQ_TYPE_EDGE_RISING)
                return -EINVAL;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
        if (gic_arch_extn.irq_set_type)
                gic_arch_extn.irq_set_type(d, type);
 
        ret = gic_configure_irq(gicirq, type, base, NULL);
 
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
        return ret;
 }
@@ -227,6 +230,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
        unsigned int cpu, shift = (gic_irq(d) % 4) * 8;
        u32 val, mask, bit;
+       unsigned long flags;
 
        if (!force)
                cpu = cpumask_any_and(mask_val, cpu_online_mask);
@@ -236,12 +240,12 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
                return -EINVAL;
 
-       raw_spin_lock(&irq_controller_lock);
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
        mask = 0xff << shift;
        bit = gic_cpu_map[cpu] << shift;
        val = readl_relaxed(reg) & ~mask;
        writel_relaxed(val | bit, reg);
-       raw_spin_unlock(&irq_controller_lock);
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
        return IRQ_SET_MASK_OK;
 }
index 3c92780bda09e17843f3cea5c7c35161e103c25c..ff48da61c94c849bf06cbb9ab9cb149515dcd626 100644 (file)
@@ -1755,7 +1755,7 @@ init_card(struct hfc_pci *hc)
                enable_hwirq(hc);
                spin_unlock_irqrestore(&hc->lock, flags);
                /* Timeout 80ms */
-               current->state = TASK_UNINTERRUPTIBLE;
+               set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout((80 * HZ) / 1000);
                printk(KERN_INFO "HFC PCI: IRQ %d count %d\n",
                       hc->irq, hc->irqcnt);
index 6a7447c304acc39e6edc422bf8f6533acfde93b5..358a574d9e8be4d2bfed217b0448c89fe458d8f6 100644 (file)
@@ -1609,7 +1609,7 @@ icn_setup(char *line)
        if (ints[0] > 1)
                membase = (unsigned long)ints[2];
        if (str && *str) {
-               strcpy(sid, str);
+               strlcpy(sid, str, sizeof(sid));
                icn_id = sid;
                if ((p = strchr(sid, ','))) {
                        *p++ = 0;
index ee035ec4526bd802a89de51c6edc099d8bbb9747..169172d2ba05c8b4187b9151975dcd1be52043c2 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 37de0173b6d2324ed15de95442df37bc5a990e16..74adcd2c967ec8680d0cfd5c9d876c93074dbe10 100644 (file)
@@ -289,9 +289,16 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
        struct request_queue *q = bdev_get_queue(where->bdev);
        unsigned short logical_block_size = queue_logical_block_size(q);
        sector_t num_sectors;
+       unsigned int uninitialized_var(special_cmd_max_sectors);
 
-       /* Reject unsupported discard requests */
-       if ((rw & REQ_DISCARD) && !blk_queue_discard(q)) {
+       /*
+        * Reject unsupported discard and write same requests.
+        */
+       if (rw & REQ_DISCARD)
+               special_cmd_max_sectors = q->limits.max_discard_sectors;
+       else if (rw & REQ_WRITE_SAME)
+               special_cmd_max_sectors = q->limits.max_write_same_sectors;
+       if ((rw & (REQ_DISCARD | REQ_WRITE_SAME)) && special_cmd_max_sectors == 0) {
                dec_count(io, region, -EOPNOTSUPP);
                return;
        }
@@ -317,7 +324,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                store_io_and_region_in_bio(bio, io, region);
 
                if (rw & REQ_DISCARD) {
-                       num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
+                       num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
                        bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
                        remaining -= num_sectors;
                } else if (rw & REQ_WRITE_SAME) {
@@ -326,7 +333,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                         */
                        dp->get_page(dp, &page, &len, &offset);
                        bio_add_page(bio, page, logical_block_size, offset);
-                       num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining);
+                       num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
                        bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
 
                        offset = 0;
index 8b204ae216ab62d354c814277dc413c34f0bf9a4..f83a0f3fc3656680c7bdba2dcd4bdaaac9f2f624 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/log2.h>
 #include <linux/dm-kcopyd.h>
 
+#include "dm.h"
+
 #include "dm-exception-store.h"
 
 #define DM_MSG_PREFIX "snapshots"
@@ -290,6 +292,16 @@ struct origin {
        struct list_head snapshots;
 };
 
+/*
+ * This structure is allocated for each origin target
+ */
+struct dm_origin {
+       struct dm_dev *dev;
+       struct dm_target *ti;
+       unsigned split_boundary;
+       struct list_head hash_list;
+};
+
 /*
  * Size of the hash table for origin volumes. If we make this
  * the size of the minors list then it should be nearly perfect
@@ -297,6 +309,7 @@ struct origin {
 #define ORIGIN_HASH_SIZE 256
 #define ORIGIN_MASK      0xFF
 static struct list_head *_origins;
+static struct list_head *_dm_origins;
 static struct rw_semaphore _origins_lock;
 
 static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done);
@@ -310,12 +323,22 @@ static int init_origin_hash(void)
        _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
                           GFP_KERNEL);
        if (!_origins) {
-               DMERR("unable to allocate memory");
+               DMERR("unable to allocate memory for _origins");
                return -ENOMEM;
        }
-
        for (i = 0; i < ORIGIN_HASH_SIZE; i++)
                INIT_LIST_HEAD(_origins + i);
+
+       _dm_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
+                             GFP_KERNEL);
+       if (!_dm_origins) {
+               DMERR("unable to allocate memory for _dm_origins");
+               kfree(_origins);
+               return -ENOMEM;
+       }
+       for (i = 0; i < ORIGIN_HASH_SIZE; i++)
+               INIT_LIST_HEAD(_dm_origins + i);
+
        init_rwsem(&_origins_lock);
 
        return 0;
@@ -324,6 +347,7 @@ static int init_origin_hash(void)
 static void exit_origin_hash(void)
 {
        kfree(_origins);
+       kfree(_dm_origins);
 }
 
 static unsigned origin_hash(struct block_device *bdev)
@@ -350,6 +374,30 @@ static void __insert_origin(struct origin *o)
        list_add_tail(&o->hash_list, sl);
 }
 
+static struct dm_origin *__lookup_dm_origin(struct block_device *origin)
+{
+       struct list_head *ol;
+       struct dm_origin *o;
+
+       ol = &_dm_origins[origin_hash(origin)];
+       list_for_each_entry (o, ol, hash_list)
+               if (bdev_equal(o->dev->bdev, origin))
+                       return o;
+
+       return NULL;
+}
+
+static void __insert_dm_origin(struct dm_origin *o)
+{
+       struct list_head *sl = &_dm_origins[origin_hash(o->dev->bdev)];
+       list_add_tail(&o->hash_list, sl);
+}
+
+static void __remove_dm_origin(struct dm_origin *o)
+{
+       list_del(&o->hash_list);
+}
+
 /*
  * _origins_lock must be held when calling this function.
  * Returns number of snapshots registered using the supplied cow device, plus:
@@ -1840,9 +1888,40 @@ static int snapshot_preresume(struct dm_target *ti)
 static void snapshot_resume(struct dm_target *ti)
 {
        struct dm_snapshot *s = ti->private;
-       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
+       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL, *snap_merging = NULL;
+       struct dm_origin *o;
+       struct mapped_device *origin_md = NULL;
+       bool must_restart_merging = false;
 
        down_read(&_origins_lock);
+
+       o = __lookup_dm_origin(s->origin->bdev);
+       if (o)
+               origin_md = dm_table_get_md(o->ti->table);
+       if (!origin_md) {
+               (void) __find_snapshots_sharing_cow(s, NULL, NULL, &snap_merging);
+               if (snap_merging)
+                       origin_md = dm_table_get_md(snap_merging->ti->table);
+       }
+       if (origin_md == dm_table_get_md(ti->table))
+               origin_md = NULL;
+       if (origin_md) {
+               if (dm_hold(origin_md))
+                       origin_md = NULL;
+       }
+
+       up_read(&_origins_lock);
+
+       if (origin_md) {
+               dm_internal_suspend_fast(origin_md);
+               if (snap_merging && test_bit(RUNNING_MERGE, &snap_merging->state_bits)) {
+                       must_restart_merging = true;
+                       stop_merge(snap_merging);
+               }
+       }
+
+       down_read(&_origins_lock);
+
        (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
        if (snap_src && snap_dest) {
                down_write(&snap_src->lock);
@@ -1851,8 +1930,16 @@ static void snapshot_resume(struct dm_target *ti)
                up_write(&snap_dest->lock);
                up_write(&snap_src->lock);
        }
+
        up_read(&_origins_lock);
 
+       if (origin_md) {
+               if (must_restart_merging)
+                       start_merge(snap_merging);
+               dm_internal_resume_fast(origin_md);
+               dm_put(origin_md);
+       }
+
        /* Now we have correct chunk size, reregister */
        reregister_snapshot(s);
 
@@ -2133,11 +2220,6 @@ static int origin_write_extent(struct dm_snapshot *merging_snap,
  * Origin: maps a linear range of a device, with hooks for snapshotting.
  */
 
-struct dm_origin {
-       struct dm_dev *dev;
-       unsigned split_boundary;
-};
-
 /*
  * Construct an origin mapping: <dev_path>
  * The context for an origin is merely a 'struct dm_dev *'
@@ -2166,6 +2248,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad_open;
        }
 
+       o->ti = ti;
        ti->private = o;
        ti->num_flush_bios = 1;
 
@@ -2180,6 +2263,7 @@ bad_alloc:
 static void origin_dtr(struct dm_target *ti)
 {
        struct dm_origin *o = ti->private;
+
        dm_put_device(ti, o->dev);
        kfree(o);
 }
@@ -2216,6 +2300,19 @@ static void origin_resume(struct dm_target *ti)
        struct dm_origin *o = ti->private;
 
        o->split_boundary = get_origin_minimum_chunksize(o->dev->bdev);
+
+       down_write(&_origins_lock);
+       __insert_dm_origin(o);
+       up_write(&_origins_lock);
+}
+
+static void origin_postsuspend(struct dm_target *ti)
+{
+       struct dm_origin *o = ti->private;
+
+       down_write(&_origins_lock);
+       __remove_dm_origin(o);
+       up_write(&_origins_lock);
 }
 
 static void origin_status(struct dm_target *ti, status_type_t type,
@@ -2258,12 +2355,13 @@ static int origin_iterate_devices(struct dm_target *ti,
 
 static struct target_type origin_target = {
        .name    = "snapshot-origin",
-       .version = {1, 8, 1},
+       .version = {1, 9, 0},
        .module  = THIS_MODULE,
        .ctr     = origin_ctr,
        .dtr     = origin_dtr,
        .map     = origin_map,
        .resume  = origin_resume,
+       .postsuspend = origin_postsuspend,
        .status  = origin_status,
        .merge   = origin_merge,
        .iterate_devices = origin_iterate_devices,
@@ -2271,7 +2369,7 @@ static struct target_type origin_target = {
 
 static struct target_type snapshot_target = {
        .name    = "snapshot",
-       .version = {1, 12, 0},
+       .version = {1, 13, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2285,7 +2383,7 @@ static struct target_type snapshot_target = {
 
 static struct target_type merge_target = {
        .name    = dm_snapshot_merge_target_name,
-       .version = {1, 2, 0},
+       .version = {1, 3, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
index 654773cb1eeea23b39db0fcf0e6fb00d91d9476d..921aafd12aee6754c373fbbd0df8941219b5c1eb 100644 (file)
@@ -2358,17 +2358,6 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
 
        case -ENODATA:
-               if (get_pool_mode(tc->pool) == PM_READ_ONLY) {
-                       /*
-                        * This block isn't provisioned, and we have no way
-                        * of doing so.
-                        */
-                       handle_unserviceable_bio(tc->pool, bio);
-                       cell_defer_no_holder(tc, virt_cell);
-                       return DM_MAPIO_SUBMITTED;
-               }
-               /* fall through */
-
        case -EWOULDBLOCK:
                thin_defer_cell(tc, virt_cell);
                return DM_MAPIO_SUBMITTED;
index 73f28802dc7abc3cb46dc38c8ef6fb5bb521e66b..8001fe9e3434734ad92c8109ef8fa860906238ce 100644 (file)
@@ -433,7 +433,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
 
        dm_get(md);
        atomic_inc(&md->open_count);
-
 out:
        spin_unlock(&_minor_lock);
 
@@ -442,16 +441,20 @@ out:
 
 static void dm_blk_close(struct gendisk *disk, fmode_t mode)
 {
-       struct mapped_device *md = disk->private_data;
+       struct mapped_device *md;
 
        spin_lock(&_minor_lock);
 
+       md = disk->private_data;
+       if (WARN_ON(!md))
+               goto out;
+
        if (atomic_dec_and_test(&md->open_count) &&
            (test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
                queue_work(deferred_remove_workqueue, &deferred_remove_work);
 
        dm_put(md);
-
+out:
        spin_unlock(&_minor_lock);
 }
 
@@ -2241,7 +2244,6 @@ static void free_dev(struct mapped_device *md)
        int minor = MINOR(disk_devt(md->disk));
 
        unlock_fs(md);
-       bdput(md->bdev);
        destroy_workqueue(md->wq);
 
        if (md->kworker_task)
@@ -2252,19 +2254,22 @@ static void free_dev(struct mapped_device *md)
                mempool_destroy(md->rq_pool);
        if (md->bs)
                bioset_free(md->bs);
-       blk_integrity_unregister(md->disk);
-       del_gendisk(md->disk);
+
        cleanup_srcu_struct(&md->io_barrier);
        free_table_devices(&md->table_devices);
-       free_minor(minor);
+       dm_stats_cleanup(&md->stats);
 
        spin_lock(&_minor_lock);
        md->disk->private_data = NULL;
        spin_unlock(&_minor_lock);
-
+       if (blk_get_integrity(md->disk))
+               blk_integrity_unregister(md->disk);
+       del_gendisk(md->disk);
        put_disk(md->disk);
        blk_cleanup_queue(md->queue);
-       dm_stats_cleanup(&md->stats);
+       bdput(md->bdev);
+       free_minor(minor);
+
        module_put(THIS_MODULE);
        kfree(md);
 }
@@ -2616,6 +2621,19 @@ void dm_get(struct mapped_device *md)
        BUG_ON(test_bit(DMF_FREEING, &md->flags));
 }
 
+int dm_hold(struct mapped_device *md)
+{
+       spin_lock(&_minor_lock);
+       if (test_bit(DMF_FREEING, &md->flags)) {
+               spin_unlock(&_minor_lock);
+               return -EBUSY;
+       }
+       dm_get(md);
+       spin_unlock(&_minor_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dm_hold);
+
 const char *dm_device_name(struct mapped_device *md)
 {
        return md->name;
@@ -2629,8 +2647,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
 
        might_sleep();
 
-       spin_lock(&_minor_lock);
        map = dm_get_live_table(md, &srcu_idx);
+
+       spin_lock(&_minor_lock);
        idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
        set_bit(DMF_FREEING, &md->flags);
        spin_unlock(&_minor_lock);
@@ -2638,10 +2657,16 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
        if (dm_request_based(md))
                flush_kthread_worker(&md->kworker);
 
+       /*
+        * Take suspend_lock so that presuspend and postsuspend methods
+        * do not race with internal suspend.
+        */
+       mutex_lock(&md->suspend_lock);
        if (!dm_suspended_md(md)) {
                dm_table_presuspend_targets(map);
                dm_table_postsuspend_targets(map);
        }
+       mutex_unlock(&md->suspend_lock);
 
        /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
        dm_put_live_table(md, srcu_idx);
@@ -3115,6 +3140,7 @@ void dm_internal_suspend_fast(struct mapped_device *md)
        flush_workqueue(md->wq);
        dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
 }
+EXPORT_SYMBOL_GPL(dm_internal_suspend_fast);
 
 void dm_internal_resume_fast(struct mapped_device *md)
 {
@@ -3126,6 +3152,7 @@ void dm_internal_resume_fast(struct mapped_device *md)
 done:
        mutex_unlock(&md->suspend_lock);
 }
+EXPORT_SYMBOL_GPL(dm_internal_resume_fast);
 
 /*-----------------------------------------------------------------
  * Event notification.
index c8d2bac4e28be4a65edb63d613b0336b7ff35783..717daad71fb101b2b97efd03b1bb41d8b35ecfe7 100644 (file)
@@ -2555,7 +2555,7 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
        return err ? err : len;
 }
 static struct rdev_sysfs_entry rdev_state =
-__ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store);
+__ATTR_PREALLOC(state, S_IRUGO|S_IWUSR, state_show, state_store);
 
 static ssize_t
 errors_show(struct md_rdev *rdev, char *page)
@@ -3638,7 +3638,8 @@ resync_start_store(struct mddev *mddev, const char *buf, size_t len)
        return err ?: len;
 }
 static struct md_sysfs_entry md_resync_start =
-__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);
+__ATTR_PREALLOC(resync_start, S_IRUGO|S_IWUSR,
+               resync_start_show, resync_start_store);
 
 /*
  * The array state can be:
@@ -3851,7 +3852,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
        return err ?: len;
 }
 static struct md_sysfs_entry md_array_state =
-__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
+__ATTR_PREALLOC(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
 
 static ssize_t
 max_corrected_read_errors_show(struct mddev *mddev, char *page) {
@@ -4101,7 +4102,7 @@ out_unlock:
 }
 
 static struct md_sysfs_entry md_metadata =
-__ATTR(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
+__ATTR_PREALLOC(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
 
 static ssize_t
 action_show(struct mddev *mddev, char *page)
@@ -4189,7 +4190,7 @@ action_store(struct mddev *mddev, const char *page, size_t len)
 }
 
 static struct md_sysfs_entry md_scan_mode =
-__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
+__ATTR_PREALLOC(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
 
 static ssize_t
 last_sync_action_show(struct mddev *mddev, char *page)
@@ -4335,7 +4336,8 @@ sync_completed_show(struct mddev *mddev, char *page)
        return sprintf(page, "%llu / %llu\n", resync, max_sectors);
 }
 
-static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
+static struct md_sysfs_entry md_sync_completed =
+       __ATTR_PREALLOC(sync_completed, S_IRUGO, sync_completed_show, NULL);
 
 static ssize_t
 min_sync_show(struct mddev *mddev, char *page)
@@ -5078,7 +5080,8 @@ int md_run(struct mddev *mddev)
        }
        if (err) {
                mddev_detach(mddev);
-               pers->free(mddev, mddev->private);
+               if (mddev->private)
+                       pers->free(mddev, mddev->private);
                module_put(pers->owner);
                bitmap_destroy(mddev);
                return err;
index a13f738a7b39f60fa340dec21612cf25b99570a7..3ed9f42ddca65e10351a1a453f16383e63c52634 100644 (file)
@@ -467,8 +467,6 @@ static int raid0_run(struct mddev *mddev)
        dump_zones(mddev);
 
        ret = md_integrity_register(mddev);
-       if (ret)
-               raid0_free(mddev, conf);
 
        return ret;
 }
index 4153da5d40111844616e8247a78e16c561602395..d34e238afa54c24ccaefbc7c6d58974dc2104be6 100644 (file)
@@ -560,7 +560,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                if (test_bit(WriteMostly, &rdev->flags)) {
                        /* Don't balance among write-mostly, just
                         * use the first as a last resort */
-                       if (best_disk < 0) {
+                       if (best_dist_disk < 0) {
                                if (is_badblock(rdev, this_sector, sectors,
                                                &first_bad, &bad_sectors)) {
                                        if (first_bad < this_sector)
@@ -569,7 +569,8 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                                        best_good_sectors = first_bad - this_sector;
                                } else
                                        best_good_sectors = sectors;
-                               best_disk = disk;
+                               best_dist_disk = disk;
+                               best_pending_disk = disk;
                        }
                        continue;
                }
index e75d48c0421a41788c9159ef7e74d22ad93d9695..cd2f96b2c57263628ef0816af3b114ad9437b740 100644 (file)
@@ -5121,12 +5121,17 @@ static inline sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int
                schedule_timeout_uninterruptible(1);
        }
        /* Need to check if array will still be degraded after recovery/resync
-        * We don't need to check the 'failed' flag as when that gets set,
-        * recovery aborts.
+        * Note in case of > 1 drive failures it's possible we're rebuilding
+        * one drive while leaving another faulty drive in array.
         */
-       for (i = 0; i < conf->raid_disks; i++)
-               if (conf->disks[i].rdev == NULL)
+       rcu_read_lock();
+       for (i = 0; i < conf->raid_disks; i++) {
+               struct md_rdev *rdev = ACCESS_ONCE(conf->disks[i].rdev);
+
+               if (rdev == NULL || test_bit(Faulty, &rdev->flags))
                        still_degraded = 1;
+       }
+       rcu_read_unlock();
 
        bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
 
index f38ec424872e362b934aaa6edd2fb21358bcb326..5615522f8d628b0f9d4b43d240d18d7bad02c835 100644 (file)
@@ -739,7 +739,7 @@ static int __init kempld_init(void)
                for (id = kempld_dmi_table;
                     id->matches[0].slot != DMI_NONE; id++)
                        if (strstr(id->ident, force_device_id))
-                               if (id->callback && id->callback(id))
+                               if (id->callback && !id->callback(id))
                                        break;
                if (id->matches[0].slot == DMI_NONE)
                        return -ENODEV;
index ede50244f265b14d950fba0448652960304fa971..dbd907d7170ebe990cb63fede374624ea03b6fd4 100644 (file)
@@ -196,18 +196,27 @@ EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register);
 int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
 {
        u16 value;
+       u8 *buf;
+       int ret;
 
        if (!data)
                return -EINVAL;
-       *data = 0;
+
+       buf = kzalloc(sizeof(u8), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT;
        value = swab16(addr);
 
-       return usb_control_msg(ucr->pusb_dev,
+       ret = usb_control_msg(ucr->pusb_dev,
                        usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, 0, data, 1, 100);
+                       value, 0, buf, 1, 100);
+       *data = *buf;
+
+       kfree(buf);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register);
 
@@ -288,18 +297,27 @@ static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status)
 int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
 {
        int ret;
+       u16 *buf;
 
        if (!status)
                return -EINVAL;
 
-       if (polling_pipe == 0)
+       if (polling_pipe == 0) {
+               buf = kzalloc(sizeof(u16), GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+
                ret = usb_control_msg(ucr->pusb_dev,
                                usb_rcvctrlpipe(ucr->pusb_dev, 0),
                                RTSX_USB_REQ_POLL,
                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               0, 0, status, 2, 100);
-       else
+                               0, 0, buf, 2, 100);
+               *status = *buf;
+
+               kfree(buf);
+       } else {
                ret = rtsx_usb_get_status_with_bulk(ucr, status);
+       }
 
        /* usb_control_msg may return positive when success */
        if (ret < 0)
index 9306219d5675442b186b0ab6381fdd246ad09e60..6ad049a08e4d9d27880e62b69a8d249207fa5a13 100644 (file)
@@ -341,6 +341,8 @@ void mei_stop(struct mei_device *dev)
 
        dev->dev_state = MEI_DEV_POWER_DOWN;
        mei_reset(dev);
+       /* move device to disabled state unconditionally */
+       dev->dev_state = MEI_DEV_DISABLED;
 
        mutex_unlock(&dev->device_lock);
 
index e9f1d8d8461353cd88831c154ae6dc43fe994772..c53f14a7ce546533c300313a54078e1bad327bf9 100644 (file)
@@ -124,7 +124,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
                    PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) {
                        ret = PTR_ERR(pwrseq->reset_gpios[i]);
 
-                       while (--i)
+                       while (i--)
                                gpiod_put(pwrseq->reset_gpios[i]);
 
                        goto clk_put;
index 5b76a173cd95d6d59c41c47d15c081ff39473c53..5897d8d8fa5a962d896e6726edde207b99575d39 100644 (file)
@@ -526,6 +526,7 @@ config MTD_NAND_SUNXI
 
 config MTD_NAND_HISI504
        tristate "Support for NAND controller on Hisilicon SoC Hip04"
+       depends on HAS_DMA
        help
          Enables support for NAND controller on Hisilicon SoC Hip04.
 
index 96b0b1d27df1b23846d09e81be2065ea59c66b7b..10b1f7a4fe50511e9fdac06242343f14df9cf71f 100644 (file)
@@ -480,6 +480,42 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
        nand_writel(info, NDCR, ndcr | int_mask);
 }
 
+static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
+{
+       if (info->ecc_bch) {
+               int timeout;
+
+               /*
+                * According to the datasheet, when reading from NDDB
+                * with BCH enabled, after each 32 bytes reads, we
+                * have to make sure that the NDSR.RDDREQ bit is set.
+                *
+                * Drain the FIFO 8 32 bits reads at a time, and skip
+                * the polling on the last read.
+                */
+               while (len > 8) {
+                       __raw_readsl(info->mmio_base + NDDB, data, 8);
+
+                       for (timeout = 0;
+                            !(nand_readl(info, NDSR) & NDSR_RDDREQ);
+                            timeout++) {
+                               if (timeout >= 5) {
+                                       dev_err(&info->pdev->dev,
+                                               "Timeout on RDDREQ while draining the FIFO\n");
+                                       return;
+                               }
+
+                               mdelay(1);
+                       }
+
+                       data += 32;
+                       len -= 8;
+               }
+       }
+
+       __raw_readsl(info->mmio_base + NDDB, data, len);
+}
+
 static void handle_data_pio(struct pxa3xx_nand_info *info)
 {
        unsigned int do_bytes = min(info->data_size, info->chunk_size);
@@ -496,14 +532,14 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
                                      DIV_ROUND_UP(info->oob_size, 4));
                break;
        case STATE_PIO_READING:
-               __raw_readsl(info->mmio_base + NDDB,
-                            info->data_buff + info->data_buff_pos,
-                            DIV_ROUND_UP(do_bytes, 4));
+               drain_fifo(info,
+                          info->data_buff + info->data_buff_pos,
+                          DIV_ROUND_UP(do_bytes, 4));
 
                if (info->oob_size > 0)
-                       __raw_readsl(info->mmio_base + NDDB,
-                                    info->oob_buff + info->oob_buff_pos,
-                                    DIV_ROUND_UP(info->oob_size, 4));
+                       drain_fifo(info,
+                                  info->oob_buff + info->oob_buff_pos,
+                                  DIV_ROUND_UP(info->oob_size, 4));
                break;
        default:
                dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
@@ -1572,6 +1608,8 @@ static int alloc_nand_resource(struct platform_device *pdev)
        int ret, irq, cs;
 
        pdata = dev_get_platdata(&pdev->dev);
+       if (pdata->num_cs <= 0)
+               return -ENODEV;
        info = devm_kzalloc(&pdev->dev, sizeof(*info) + (sizeof(*mtd) +
                            sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
        if (!info)
index da4c79259f67f3e2bd63a62570845eb10c89e989..16e34b37d134cee7797651f4ad8586db8d11faa1 100644 (file)
@@ -425,9 +425,10 @@ retry:
                                        ubi_warn(ubi, "corrupted VID header at PEB %d, LEB %d:%d",
                                                 pnum, vol_id, lnum);
                                        err = -EBADMSG;
-                               } else
+                               } else {
                                        err = -EINVAL;
                                        ubi_ro_mode(ubi);
+                               }
                        }
                        goto out_free;
                } else if (err == UBI_IO_BITFLIPS)
index 84673ebcf428846fadf26ae881c39172fd45d612..df51d6025a9017413500046edb78401abe0dfdb3 100644 (file)
@@ -157,7 +157,7 @@ config IPVLAN
       making it transparent to the connected L2 switch.
 
       Ipvlan devices can be added using the "ip" command from the
-      iproute2 package starting with the iproute2-X.Y.ZZ release:
+      iproute2 package starting with the iproute2-3.19 release:
 
       "ip link add link <main-dev> [ NAME ] type ipvlan"
 
index 4ce6ca5f3d365a48ab554c7477b157437fff9357..dc6b78e5342f937e6b3b2d498d4694bc0d0fe6c0 100644 (file)
@@ -40,7 +40,7 @@ config DEV_APPLETALK
 
 config LTPC
        tristate "Apple/Farallon LocalTalk PC support"
-       depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API
+       depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API && VIRT_TO_BUS
        help
          This allows you to use the AppleTalk PC card to connect to LocalTalk
          networks. The card is also known as the Farallon PhoneNet PC card.
index b979c265fc51d0a09c48ff4216a8b055ebcd1c26..089a4028859d121d5611d04dde0139196753fb00 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 98d73aab52fe962888a675d1293ae69f9731f7d0..58808f6514520c869631b356d6476f8cbc060a14 100644 (file)
@@ -131,7 +131,7 @@ config CAN_RCAR
 
 config CAN_XILINXCAN
        tristate "Xilinx CAN"
-       depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
+       depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST
        depends on COMMON_CLK && HAS_IOMEM
        ---help---
          Xilinx CAN driver. This driver supports both soft AXI CAN IP and
index 3c82e02e3daee633b65274abce48a4ae71257d5a..b0f69248cb71cd5642f9e34f67d291ee8a842dd2 100644 (file)
@@ -579,6 +579,10 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
 
@@ -603,6 +607,10 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
 
index 80c46ad4cee439d2015b3ee7de66d578f54afd0b..ad0a7e8c2c2bdf33626824645a8180d8e6d900ff 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 009acc8641fc557cb580cb688983daf041519e4b..8b4d3e6875eb17e6bca38c812132953d0c5ce2c2 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 2928f7003041d92c099d31d19621f1a429ea0848..57611fd91229a4580987b3519d56b8913f185411 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 1ba7c25002e1e27ec1a9333412c175edb0f5594a..e8fc4952c6b074f80a2af132d2bc161e7fd3d8c7 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 962c3f027383a7a1e28077b4227b9c40f7542518..a9221ad9f1a0a0387de1ebf8470c0d360e895773 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 ee9f650d50264bb74771783b65e860b2aabb3d46..7b7053d3c5fad20e07a75eb5ea987743b51484ba 100644 (file)
@@ -105,8 +105,8 @@ static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off)  \
 {                                                                      \
        u32 indir, dir;                                                 \
        spin_lock(&priv->indir_lock);                                   \
-       indir = reg_readl(priv, REG_DIR_DATA_READ);                     \
        dir = __raw_readl(priv->name + off);                            \
+       indir = reg_readl(priv, REG_DIR_DATA_READ);                     \
        spin_unlock(&priv->indir_lock);                                 \
        return (u64)indir << 32 | dir;                                  \
 }                                                                      \
index 7769c05543f17fcc8432cac6145ebdd70c4fc5da..ec6eac1f8c95ab79d33209e272a31f71484b0f62 100644 (file)
@@ -484,11 +484,8 @@ static int axnet_open(struct net_device *dev)
     link->open++;
 
     info->link_status = 0x00;
-    init_timer(&info->watchdog);
-    info->watchdog.function = ei_watchdog;
-    info->watchdog.data = (u_long)dev;
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
+    setup_timer(&info->watchdog, ei_watchdog, (u_long)dev);
+    mod_timer(&info->watchdog, jiffies + HZ);
 
     return ax_open(dev);
 } /* axnet_open */
index 9fb7b9d4fd6c6595f7642d859678bc3097998750..2777289a26c0419f855926ef028942074ca62a2f 100644 (file)
@@ -918,11 +918,8 @@ static int pcnet_open(struct net_device *dev)
 
     info->phy_id = info->eth_phy;
     info->link_status = 0x00;
-    init_timer(&info->watchdog);
-    info->watchdog.function = ei_watchdog;
-    info->watchdog.data = (u_long)dev;
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
+    setup_timer(&info->watchdog, ei_watchdog, (u_long)dev);
+    mod_timer(&info->watchdog, jiffies + HZ);
 
     return ei_open(dev);
 } /* pcnet_open */
index 760c72c6e2acd50ba8472e4b4dd77170c2c381d6..6725dc00750bd6da367396bceb33adaac10842d0 100644 (file)
@@ -376,7 +376,8 @@ static int tse_rx(struct altera_tse_private *priv, int limit)
        u16 pktlength;
        u16 pktstatus;
 
-       while ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) {
+       while (((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) &&
+              (count < limit))  {
                pktstatus = rxstatus >> 16;
                pktlength = rxstatus & 0xffff;
 
@@ -491,28 +492,27 @@ static int tse_poll(struct napi_struct *napi, int budget)
        struct altera_tse_private *priv =
                        container_of(napi, struct altera_tse_private, napi);
        int rxcomplete = 0;
-       int txcomplete = 0;
        unsigned long int flags;
 
-       txcomplete = tse_tx_complete(priv);
+       tse_tx_complete(priv);
 
        rxcomplete = tse_rx(priv, budget);
 
-       if (rxcomplete >= budget || txcomplete > 0)
-               return rxcomplete;
+       if (rxcomplete < budget) {
 
-       napi_gro_flush(napi, false);
-       __napi_complete(napi);
+               napi_gro_flush(napi, false);
+               __napi_complete(napi);
 
-       netdev_dbg(priv->dev,
-                  "NAPI Complete, did %d packets with budget %d\n",
-                  txcomplete+rxcomplete, budget);
+               netdev_dbg(priv->dev,
+                          "NAPI Complete, did %d packets with budget %d\n",
+                          rxcomplete, budget);
 
-       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
-       priv->dmaops->enable_rxirq(priv);
-       priv->dmaops->enable_txirq(priv);
-       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
-       return rxcomplete + txcomplete;
+               spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+               priv->dmaops->enable_rxirq(priv);
+               priv->dmaops->enable_txirq(priv);
+               spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+       }
+       return rxcomplete;
 }
 
 /* DMA TX & RX FIFO interrupt routing
@@ -521,7 +521,6 @@ static irqreturn_t altera_isr(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct altera_tse_private *priv;
-       unsigned long int flags;
 
        if (unlikely(!dev)) {
                pr_err("%s: invalid dev pointer\n", __func__);
@@ -529,20 +528,20 @@ static irqreturn_t altera_isr(int irq, void *dev_id)
        }
        priv = netdev_priv(dev);
 
-       /* turn off desc irqs and enable napi rx */
-       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       spin_lock(&priv->rxdma_irq_lock);
+       /* reset IRQs */
+       priv->dmaops->clear_rxirq(priv);
+       priv->dmaops->clear_txirq(priv);
+       spin_unlock(&priv->rxdma_irq_lock);
 
        if (likely(napi_schedule_prep(&priv->napi))) {
+               spin_lock(&priv->rxdma_irq_lock);
                priv->dmaops->disable_rxirq(priv);
                priv->dmaops->disable_txirq(priv);
+               spin_unlock(&priv->rxdma_irq_lock);
                __napi_schedule(&priv->napi);
        }
 
-       /* reset IRQs */
-       priv->dmaops->clear_rxirq(priv);
-       priv->dmaops->clear_txirq(priv);
-
-       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
 
        return IRQ_HANDLED;
 }
@@ -1399,7 +1398,7 @@ static int altera_tse_probe(struct platform_device *pdev)
        }
 
        if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
-                                &priv->rx_fifo_depth)) {
+                                &priv->tx_fifo_depth)) {
                dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n");
                ret = -ENXIO;
                goto err_free_netdev;
index 11d6e6561df159c3dc9dff28fc504e945a77f47b..15a8190a6f75f61908f5ba968d37451e2f982897 100644 (file)
@@ -1543,7 +1543,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 {
        struct pcnet32_private *lp;
        int i, media;
-       int fdx, mii, fset, dxsuflo;
+       int fdx, mii, fset, dxsuflo, sram;
        int chip_version;
        char *chipname;
        struct net_device *dev;
@@ -1580,7 +1580,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
        }
 
        /* initialize variables */
-       fdx = mii = fset = dxsuflo = 0;
+       fdx = mii = fset = dxsuflo = sram = 0;
        chip_version = (chip_version >> 12) & 0xffff;
 
        switch (chip_version) {
@@ -1613,6 +1613,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                chipname = "PCnet/FAST III 79C973";     /* PCI */
                fdx = 1;
                mii = 1;
+               sram = 1;
                break;
        case 0x2626:
                chipname = "PCnet/Home 79C978"; /* PCI */
@@ -1636,6 +1637,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                chipname = "PCnet/FAST III 79C975";     /* PCI */
                fdx = 1;
                mii = 1;
+               sram = 1;
                break;
        case 0x2628:
                chipname = "PCnet/PRO 79C976";
@@ -1664,6 +1666,31 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                dxsuflo = 1;
        }
 
+       /*
+        * The Am79C973/Am79C975 controllers come with 12K of SRAM
+        * which we can use for the Tx/Rx buffers but most importantly,
+        * the use of SRAM allow us to use the BCR18:NOUFLO bit to avoid
+        * Tx fifo underflows.
+        */
+       if (sram) {
+               /*
+                * The SRAM is being configured in two steps. First we
+                * set the SRAM size in the BCR25:SRAM_SIZE bits. According
+                * to the datasheet, each bit corresponds to a 512-byte
+                * page so we can have at most 24 pages. The SRAM_SIZE
+                * holds the value of the upper 8 bits of the 16-bit SRAM size.
+                * The low 8-bits start at 0x00 and end at 0xff. So the
+                * address range is from 0x0000 up to 0x17ff. Therefore,
+                * the SRAM_SIZE is set to 0x17. The next step is to set
+                * the BCR26:SRAM_BND midway through so the Tx and Rx
+                * buffers can share the SRAM equally.
+                */
+               a->write_bcr(ioaddr, 25, 0x17);
+               a->write_bcr(ioaddr, 26, 0xc);
+               /* And finally enable the NOUFLO bit */
+               a->write_bcr(ioaddr, 18, a->read_bcr(ioaddr, 18) | (1 << 11));
+       }
+
        dev = alloc_etherdev(sizeof(*lp));
        if (!dev) {
                ret = -ENOMEM;
index b93d4404d975571f0f4033f06f4de15b576156d3..885b02b5be07f6732fc0540684cb7875aeec1140 100644 (file)
@@ -609,6 +609,68 @@ static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del)
        }
 }
 
+static int xgbe_request_irqs(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_channel *channel;
+       struct net_device *netdev = pdata->netdev;
+       unsigned int i;
+       int ret;
+
+       ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
+                              netdev->name, pdata);
+       if (ret) {
+               netdev_alert(netdev, "error requesting irq %d\n",
+                            pdata->dev_irq);
+               return ret;
+       }
+
+       if (!pdata->per_channel_irq)
+               return 0;
+
+       channel = pdata->channel;
+       for (i = 0; i < pdata->channel_count; i++, channel++) {
+               snprintf(channel->dma_irq_name,
+                        sizeof(channel->dma_irq_name) - 1,
+                        "%s-TxRx-%u", netdev_name(netdev),
+                        channel->queue_index);
+
+               ret = devm_request_irq(pdata->dev, channel->dma_irq,
+                                      xgbe_dma_isr, 0,
+                                      channel->dma_irq_name, channel);
+               if (ret) {
+                       netdev_alert(netdev, "error requesting irq %d\n",
+                                    channel->dma_irq);
+                       goto err_irq;
+               }
+       }
+
+       return 0;
+
+err_irq:
+       /* Using an unsigned int, 'i' will go to UINT_MAX and exit */
+       for (i--, channel--; i < pdata->channel_count; i--, channel--)
+               devm_free_irq(pdata->dev, channel->dma_irq, channel);
+
+       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
+
+       return ret;
+}
+
+static void xgbe_free_irqs(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_channel *channel;
+       unsigned int i;
+
+       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
+
+       if (!pdata->per_channel_irq)
+               return;
+
+       channel = pdata->channel;
+       for (i = 0; i < pdata->channel_count; i++, channel++)
+               devm_free_irq(pdata->dev, channel->dma_irq, channel);
+}
+
 void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata)
 {
        struct xgbe_hw_if *hw_if = &pdata->hw_if;
@@ -810,20 +872,20 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
                return -EINVAL;
        }
 
-       phy_stop(pdata->phydev);
-
        spin_lock_irqsave(&pdata->lock, flags);
 
        if (caller == XGMAC_DRIVER_CONTEXT)
                netif_device_detach(netdev);
 
        netif_tx_stop_all_queues(netdev);
-       xgbe_napi_disable(pdata, 0);
 
-       /* Powerdown Tx/Rx */
        hw_if->powerdown_tx(pdata);
        hw_if->powerdown_rx(pdata);
 
+       xgbe_napi_disable(pdata, 0);
+
+       phy_stop(pdata->phydev);
+
        pdata->power_down = 1;
 
        spin_unlock_irqrestore(&pdata->lock, flags);
@@ -854,14 +916,14 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
 
        phy_start(pdata->phydev);
 
-       /* Enable Tx/Rx */
+       xgbe_napi_enable(pdata, 0);
+
        hw_if->powerup_tx(pdata);
        hw_if->powerup_rx(pdata);
 
        if (caller == XGMAC_DRIVER_CONTEXT)
                netif_device_attach(netdev);
 
-       xgbe_napi_enable(pdata, 0);
        netif_tx_start_all_queues(netdev);
 
        spin_unlock_irqrestore(&pdata->lock, flags);
@@ -875,6 +937,7 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
 {
        struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct net_device *netdev = pdata->netdev;
+       int ret;
 
        DBGPR("-->xgbe_start\n");
 
@@ -884,17 +947,31 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
 
        phy_start(pdata->phydev);
 
+       xgbe_napi_enable(pdata, 1);
+
+       ret = xgbe_request_irqs(pdata);
+       if (ret)
+               goto err_napi;
+
        hw_if->enable_tx(pdata);
        hw_if->enable_rx(pdata);
 
        xgbe_init_tx_timers(pdata);
 
-       xgbe_napi_enable(pdata, 1);
        netif_tx_start_all_queues(netdev);
 
        DBGPR("<--xgbe_start\n");
 
        return 0;
+
+err_napi:
+       xgbe_napi_disable(pdata, 1);
+
+       phy_stop(pdata->phydev);
+
+       hw_if->exit(pdata);
+
+       return ret;
 }
 
 static void xgbe_stop(struct xgbe_prv_data *pdata)
@@ -907,16 +984,21 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
 
        DBGPR("-->xgbe_stop\n");
 
-       phy_stop(pdata->phydev);
-
        netif_tx_stop_all_queues(netdev);
-       xgbe_napi_disable(pdata, 1);
 
        xgbe_stop_tx_timers(pdata);
 
        hw_if->disable_tx(pdata);
        hw_if->disable_rx(pdata);
 
+       xgbe_free_irqs(pdata);
+
+       xgbe_napi_disable(pdata, 1);
+
+       phy_stop(pdata->phydev);
+
+       hw_if->exit(pdata);
+
        channel = pdata->channel;
        for (i = 0; i < pdata->channel_count; i++, channel++) {
                if (!channel->tx_ring)
@@ -931,10 +1013,6 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
 
 static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
 {
-       struct xgbe_channel *channel;
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
-       unsigned int i;
-
        DBGPR("-->xgbe_restart_dev\n");
 
        /* If not running, "restart" will happen on open */
@@ -942,19 +1020,10 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
                return;
 
        xgbe_stop(pdata);
-       synchronize_irq(pdata->dev_irq);
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++)
-                       synchronize_irq(channel->dma_irq);
-       }
 
        xgbe_free_tx_data(pdata);
        xgbe_free_rx_data(pdata);
 
-       /* Issue software reset to device */
-       hw_if->exit(pdata);
-
        xgbe_start(pdata);
 
        DBGPR("<--xgbe_restart_dev\n");
@@ -1283,10 +1352,7 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata,
 static int xgbe_open(struct net_device *netdev)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct xgbe_desc_if *desc_if = &pdata->desc_if;
-       struct xgbe_channel *channel = NULL;
-       unsigned int i = 0;
        int ret;
 
        DBGPR("-->xgbe_open\n");
@@ -1329,55 +1395,14 @@ static int xgbe_open(struct net_device *netdev)
        INIT_WORK(&pdata->restart_work, xgbe_restart);
        INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp);
 
-       /* Request interrupts */
-       ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
-                              netdev->name, pdata);
-       if (ret) {
-               netdev_alert(netdev, "error requesting irq %d\n",
-                            pdata->dev_irq);
-               goto err_rings;
-       }
-
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++) {
-                       snprintf(channel->dma_irq_name,
-                                sizeof(channel->dma_irq_name) - 1,
-                                "%s-TxRx-%u", netdev_name(netdev),
-                                channel->queue_index);
-
-                       ret = devm_request_irq(pdata->dev, channel->dma_irq,
-                                              xgbe_dma_isr, 0,
-                                              channel->dma_irq_name, channel);
-                       if (ret) {
-                               netdev_alert(netdev,
-                                            "error requesting irq %d\n",
-                                            channel->dma_irq);
-                               goto err_irq;
-                       }
-               }
-       }
-
        ret = xgbe_start(pdata);
        if (ret)
-               goto err_start;
+               goto err_rings;
 
        DBGPR("<--xgbe_open\n");
 
        return 0;
 
-err_start:
-       hw_if->exit(pdata);
-
-err_irq:
-       if (pdata->per_channel_irq) {
-               /* Using an unsigned int, 'i' will go to UINT_MAX and exit */
-               for (i--, channel--; i < pdata->channel_count; i--, channel--)
-                       devm_free_irq(pdata->dev, channel->dma_irq, channel);
-       }
-
-       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
-
 err_rings:
        desc_if->free_ring_resources(pdata);
 
@@ -1399,30 +1424,16 @@ err_phy_init:
 static int xgbe_close(struct net_device *netdev)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
-       struct xgbe_hw_if *hw_if = &pdata->hw_if;
        struct xgbe_desc_if *desc_if = &pdata->desc_if;
-       struct xgbe_channel *channel;
-       unsigned int i;
 
        DBGPR("-->xgbe_close\n");
 
        /* Stop the device */
        xgbe_stop(pdata);
 
-       /* Issue software reset to device */
-       hw_if->exit(pdata);
-
        /* Free the ring descriptors and buffers */
        desc_if->free_ring_resources(pdata);
 
-       /* Release the interrupts */
-       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
-       if (pdata->per_channel_irq) {
-               channel = pdata->channel;
-               for (i = 0; i < pdata->channel_count; i++, channel++)
-                       devm_free_irq(pdata->dev, channel->dma_irq, channel);
-       }
-
        /* Free the channel and ring structures */
        xgbe_free_channels(pdata);
 
index 869d97fcf7810ff9abb7a2cc6c7ade6e49ceb2df..b927021c6c4030c5f63abd9644aac7169d8b6034 100644 (file)
@@ -593,7 +593,7 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
        if (!xgene_ring_mgr_init(pdata))
                return -ENODEV;
 
-       if (!efi_enabled(EFI_BOOT)) {
+       if (pdata->clk) {
                clk_prepare_enable(pdata->clk);
                clk_disable_unprepare(pdata->clk);
                clk_prepare_enable(pdata->clk);
index 4de62b210c85bab8e3d172234f24381da7a66276..635a83be7e5ec5bec5670ceebca692abd9257260 100644 (file)
@@ -1025,6 +1025,8 @@ static int xgene_enet_remove(struct platform_device *pdev)
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xgene_enet_acpi_match[] = {
        { "APMC0D05", },
+       { "APMC0D30", },
+       { "APMC0D31", },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
@@ -1033,6 +1035,8 @@ MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
 #ifdef CONFIG_OF
 static struct of_device_id xgene_enet_of_match[] = {
        {.compatible = "apm,xgene-enet",},
+       {.compatible = "apm,xgene1-sgenet",},
+       {.compatible = "apm,xgene1-xgenet",},
        {},
 };
 
index 21206d33b638cf3a76e67abeb0520d71a0310b29..a7f2cc3e485eebfae962fe24cfc1142021a74cde 100644 (file)
@@ -486,7 +486,7 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
 {
        struct bcm_enet_priv *priv;
        struct net_device *dev;
-       int tx_work_done, rx_work_done;
+       int rx_work_done;
 
        priv = container_of(napi, struct bcm_enet_priv, napi);
        dev = priv->net_dev;
@@ -498,14 +498,14 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
                         ENETDMAC_IR, priv->tx_chan);
 
        /* reclaim sent skb */
-       tx_work_done = bcm_enet_tx_reclaim(dev, 0);
+       bcm_enet_tx_reclaim(dev, 0);
 
        spin_lock(&priv->rx_lock);
        rx_work_done = bcm_enet_receive_queue(dev, budget);
        spin_unlock(&priv->rx_lock);
 
-       if (rx_work_done >= budget || tx_work_done > 0) {
-               /* rx/tx queue is not yet empty/clean */
+       if (rx_work_done >= budget) {
+               /* rx queue is not yet empty/clean */
                return rx_work_done;
        }
 
index 5b308a4a4d0eccc35c641967fcf2459ec736f094..783543ad1fcfa1a4976090e0797f7f15f29a1724 100644 (file)
@@ -274,9 +274,9 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
        /* RBUF misc statistics */
        STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR),
        STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR),
-       STAT_MIB_RX("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
-       STAT_MIB_RX("rx_dma_failed", mib.rx_dma_failed),
-       STAT_MIB_TX("tx_dma_failed", mib.tx_dma_failed),
+       STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
+       STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed),
+       STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed),
 };
 
 #define BCM_SYSPORT_STATS_LEN  ARRAY_SIZE(bcm_sysport_gstrings_stats)
@@ -345,6 +345,7 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv)
                s = &bcm_sysport_gstrings_stats[i];
                switch (s->type) {
                case BCM_SYSPORT_STAT_NETDEV:
+               case BCM_SYSPORT_STAT_SOFT:
                        continue;
                case BCM_SYSPORT_STAT_MIB_RX:
                case BCM_SYSPORT_STAT_MIB_TX:
index fc19417d82a505dc61c9f25a940f891522763e00..7e3d87a88c76a81e2c36b65559d8b2b0bcf34217 100644 (file)
@@ -570,6 +570,7 @@ enum bcm_sysport_stat_type {
        BCM_SYSPORT_STAT_RUNT,
        BCM_SYSPORT_STAT_RXCHK,
        BCM_SYSPORT_STAT_RBUF,
+       BCM_SYSPORT_STAT_SOFT,
 };
 
 /* Macros to help define ethtool statistics */
@@ -590,6 +591,7 @@ enum bcm_sysport_stat_type {
 #define STAT_MIB_RX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_RX)
 #define STAT_MIB_TX(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_MIB_TX)
 #define STAT_RUNT(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_RUNT)
+#define STAT_MIB_SOFT(str, m) STAT_MIB(str, m, BCM_SYSPORT_STAT_SOFT)
 
 #define STAT_RXCHK(str, m, ofs) { \
        .stat_string = str, \
index 676ffe09318073e33b707d46423bdcf780451750..0469f72c6e7e8e01147446a528d5771a147b5cc6 100644 (file)
@@ -302,9 +302,6 @@ static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
        slot->skb = skb;
        slot->dma_addr = dma_addr;
 
-       if (slot->dma_addr & 0xC0000000)
-               bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
-
        return 0;
 }
 
@@ -505,8 +502,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                                  ring->mmio_base);
                        goto err_dma_free;
                }
-               if (ring->dma_base & 0xC0000000)
-                       bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
 
                ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
                                                      BGMAC_DMA_RING_TX);
@@ -536,8 +531,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                        err = -ENOMEM;
                        goto err_dma_free;
                }
-               if (ring->dma_base & 0xC0000000)
-                       bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
 
                ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
                                                      BGMAC_DMA_RING_RX);
index 756053c028becff93c62cfcdbd6e1f635594cc01..4085c4b310470b6ebf718121fa423d2995dcb8ef 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 7155e1d2c208c7253b846ee954086fef5fd574da..1ec635f549944f87e0c0df4eb0816dcf33d90706 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 e5aca2de1871350f3e47a788c4360b461c02a039..cfe3c7695455e16eab516e0f99db6ee6b7e58879 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 d1608297c773746237a8faf3697277afcbe45918..800ab44a07cecd721c8b12f0c5b8602e1124a0dd 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 2beceaefdeea7aa5ac53f6a3028cd0fbcacbc51a..965539a9dabe7e4702e1ba6b382aefc69fb26fac 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 ff83c46bc38961561441814813f24d9b33da42ac..6befde61c203461a27ac0298d619f4f78b7c366e 100644 (file)
@@ -487,6 +487,7 @@ enum bcmgenet_stat_type {
        BCMGENET_STAT_MIB_TX,
        BCMGENET_STAT_RUNT,
        BCMGENET_STAT_MISC,
+       BCMGENET_STAT_SOFT,
 };
 
 struct bcmgenet_stats {
@@ -515,6 +516,7 @@ struct bcmgenet_stats {
 #define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX)
 #define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX)
 #define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT)
+#define STAT_GENET_SOFT_MIB(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_SOFT)
 
 #define STAT_GENET_MISC(str, m, offset) { \
        .stat_string = str, \
@@ -614,9 +616,9 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = {
                        UMAC_RBUF_OVFL_CNT),
        STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT),
        STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT),
-       STAT_GENET_MIB_RX("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
-       STAT_GENET_MIB_RX("rx_dma_failed", mib.rx_dma_failed),
-       STAT_GENET_MIB_TX("tx_dma_failed", mib.tx_dma_failed),
+       STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
+       STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed),
+       STAT_GENET_SOFT_MIB("tx_dma_failed", mib.tx_dma_failed),
 };
 
 #define BCMGENET_STATS_LEN     ARRAY_SIZE(bcmgenet_gstrings_stats)
@@ -668,6 +670,7 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
                s = &bcmgenet_gstrings_stats[i];
                switch (s->type) {
                case BCMGENET_STAT_NETDEV:
+               case BCMGENET_STAT_SOFT:
                        continue;
                case BCMGENET_STAT_MIB_RX:
                case BCMGENET_STAT_MIB_TX:
@@ -971,13 +974,14 @@ static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv,
 }
 
 /* Unlocked version of the reclaim routine */
-static void __bcmgenet_tx_reclaim(struct net_device *dev,
-                                 struct bcmgenet_tx_ring *ring)
+static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
+                                         struct bcmgenet_tx_ring *ring)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        int last_tx_cn, last_c_index, num_tx_bds;
        struct enet_cb *tx_cb_ptr;
        struct netdev_queue *txq;
+       unsigned int pkts_compl = 0;
        unsigned int bds_compl;
        unsigned int c_index;
 
@@ -1005,6 +1009,7 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
                tx_cb_ptr = ring->cbs + last_c_index;
                bds_compl = 0;
                if (tx_cb_ptr->skb) {
+                       pkts_compl++;
                        bds_compl = skb_shinfo(tx_cb_ptr->skb)->nr_frags + 1;
                        dev->stats.tx_bytes += tx_cb_ptr->skb->len;
                        dma_unmap_single(&dev->dev,
@@ -1028,23 +1033,45 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev,
                last_c_index &= (num_tx_bds - 1);
        }
 
-       if (ring->free_bds > (MAX_SKB_FRAGS + 1))
-               ring->int_disable(priv, ring);
-
-       if (netif_tx_queue_stopped(txq))
-               netif_tx_wake_queue(txq);
+       if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
+               if (netif_tx_queue_stopped(txq))
+                       netif_tx_wake_queue(txq);
+       }
 
        ring->c_index = c_index;
+
+       return pkts_compl;
 }
 
-static void bcmgenet_tx_reclaim(struct net_device *dev,
+static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
                                struct bcmgenet_tx_ring *ring)
 {
+       unsigned int released;
        unsigned long flags;
 
        spin_lock_irqsave(&ring->lock, flags);
-       __bcmgenet_tx_reclaim(dev, ring);
+       released = __bcmgenet_tx_reclaim(dev, ring);
        spin_unlock_irqrestore(&ring->lock, flags);
+
+       return released;
+}
+
+static int bcmgenet_tx_poll(struct napi_struct *napi, int budget)
+{
+       struct bcmgenet_tx_ring *ring =
+               container_of(napi, struct bcmgenet_tx_ring, napi);
+       unsigned int work_done = 0;
+
+       work_done = bcmgenet_tx_reclaim(ring->priv->dev, ring);
+
+       if (work_done == 0) {
+               napi_complete(napi);
+               ring->int_enable(ring->priv, ring);
+
+               return 0;
+       }
+
+       return budget;
 }
 
 static void bcmgenet_tx_reclaim_all(struct net_device *dev)
@@ -1302,10 +1329,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
        bcmgenet_tdma_ring_writel(priv, ring->index,
                                  ring->prod_index, TDMA_PROD_INDEX);
 
-       if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) {
+       if (ring->free_bds <= (MAX_SKB_FRAGS + 1))
                netif_tx_stop_queue(txq);
-               ring->int_enable(priv, ring);
-       }
 
 out:
        spin_unlock_irqrestore(&ring->lock, flags);
@@ -1621,6 +1646,7 @@ static int init_umac(struct bcmgenet_priv *priv)
        struct device *kdev = &priv->pdev->dev;
        int ret;
        u32 reg, cpu_mask_clear;
+       int index;
 
        dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n");
 
@@ -1647,7 +1673,7 @@ static int init_umac(struct bcmgenet_priv *priv)
 
        bcmgenet_intr_disable(priv);
 
-       cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE;
+       cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_TXDMA_BDONE;
 
        dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__);
 
@@ -1674,6 +1700,10 @@ static int init_umac(struct bcmgenet_priv *priv)
 
        bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR);
 
+       for (index = 0; index < priv->hw_params->tx_queues; index++)
+               bcmgenet_intrl2_1_writel(priv, (1 << index),
+                                        INTRL2_CPU_MASK_CLEAR);
+
        /* Enable rx/tx engine.*/
        dev_dbg(kdev, "done init umac\n");
 
@@ -1693,6 +1723,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
        unsigned int first_bd;
 
        spin_lock_init(&ring->lock);
+       ring->priv = priv;
+       netif_napi_add(priv->dev, &ring->napi, bcmgenet_tx_poll, 64);
        ring->index = index;
        if (index == DESC_INDEX) {
                ring->queue = 0;
@@ -1738,6 +1770,17 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
                                  TDMA_WRITE_PTR);
        bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1,
                                  DMA_END_ADDR);
+
+       napi_enable(&ring->napi);
+}
+
+static void bcmgenet_fini_tx_ring(struct bcmgenet_priv *priv,
+                                 unsigned int index)
+{
+       struct bcmgenet_tx_ring *ring = &priv->tx_rings[index];
+
+       napi_disable(&ring->napi);
+       netif_napi_del(&ring->napi);
 }
 
 /* Initialize a RDMA ring */
@@ -1907,7 +1950,7 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv)
        return ret;
 }
 
-static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
+static void __bcmgenet_fini_dma(struct bcmgenet_priv *priv)
 {
        int i;
 
@@ -1926,6 +1969,18 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
        kfree(priv->tx_cbs);
 }
 
+static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
+{
+       int i;
+
+       bcmgenet_fini_tx_ring(priv, DESC_INDEX);
+
+       for (i = 0; i < priv->hw_params->tx_queues; i++)
+               bcmgenet_fini_tx_ring(priv, i);
+
+       __bcmgenet_fini_dma(priv);
+}
+
 /* init_edma: Initialize DMA control register */
 static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
 {
@@ -1952,7 +2007,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
        priv->tx_cbs = kcalloc(priv->num_tx_bds, sizeof(struct enet_cb),
                               GFP_KERNEL);
        if (!priv->tx_cbs) {
-               bcmgenet_fini_dma(priv);
+               __bcmgenet_fini_dma(priv);
                return -ENOMEM;
        }
 
@@ -1975,9 +2030,6 @@ static int bcmgenet_poll(struct napi_struct *napi, int budget)
                        struct bcmgenet_priv, napi);
        unsigned int work_done;
 
-       /* tx reclaim */
-       bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
-
        work_done = bcmgenet_desc_rx(priv, budget);
 
        /* Advancing our consumer index*/
@@ -2022,28 +2074,34 @@ static void bcmgenet_irq_task(struct work_struct *work)
 static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
 {
        struct bcmgenet_priv *priv = dev_id;
+       struct bcmgenet_tx_ring *ring;
        unsigned int index;
 
        /* Save irq status for bottom-half processing. */
        priv->irq1_stat =
                bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
-               ~priv->int1_mask;
+               ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
        /* clear interrupts */
        bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
 
        netif_dbg(priv, intr, priv->dev,
                  "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
+
        /* Check the MBDONE interrupts.
         * packet is done, reclaim descriptors
         */
-       if (priv->irq1_stat & 0x0000ffff) {
-               index = 0;
-               for (index = 0; index < 16; index++) {
-                       if (priv->irq1_stat & (1 << index))
-                               bcmgenet_tx_reclaim(priv->dev,
-                                                   &priv->tx_rings[index]);
+       for (index = 0; index < priv->hw_params->tx_queues; index++) {
+               if (!(priv->irq1_stat & BIT(index)))
+                       continue;
+
+               ring = &priv->tx_rings[index];
+
+               if (likely(napi_schedule_prep(&ring->napi))) {
+                       ring->int_disable(priv, ring);
+                       __napi_schedule(&ring->napi);
                }
        }
+
        return IRQ_HANDLED;
 }
 
@@ -2075,8 +2133,12 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
        }
        if (priv->irq0_stat &
                        (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE)) {
-               /* Tx reclaim */
-               bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
+               struct bcmgenet_tx_ring *ring = &priv->tx_rings[DESC_INDEX];
+
+               if (likely(napi_schedule_prep(&ring->napi))) {
+                       ring->int_disable(priv, ring);
+                       __napi_schedule(&ring->napi);
+               }
        }
        if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R |
                                UMAC_IRQ_PHY_DET_F |
index b36ddec0cc0a3c5d1c64f9c2818a4b44464c41f8..0d370d168aee0ea24924fbc3afc011f3a8697841 100644 (file)
@@ -520,6 +520,7 @@ struct bcmgenet_hw_params {
 
 struct bcmgenet_tx_ring {
        spinlock_t      lock;           /* ring lock */
+       struct napi_struct napi;        /* NAPI per tx queue */
        unsigned int    index;          /* ring index */
        unsigned int    queue;          /* queue index */
        struct enet_cb  *cbs;           /* tx ring buffer control block*/
@@ -534,6 +535,7 @@ struct bcmgenet_tx_ring {
                           struct bcmgenet_tx_ring *);
        void (*int_disable)(struct bcmgenet_priv *priv,
                            struct bcmgenet_tx_ring *);
+       struct bcmgenet_priv *priv;
 };
 
 /* device context */
index 149a0d70c10883f3f769904ef6ae2ca6b2f66f8e..b97122926d3aa91210a8945d45f268d370c86ee4 100644 (file)
@@ -73,15 +73,17 @@ int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
                return -EINVAL;
 
+       reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
        if (wol->wolopts & WAKE_MAGICSECURE) {
                bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
                                     UMAC_MPD_PW_MS);
                bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
                                     UMAC_MPD_PW_LS);
-               reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
                reg |= MPD_PW_EN;
-               bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+       } else {
+               reg &= ~MPD_PW_EN;
        }
+       bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
        /* Flag the device and relevant IRQ as wakeup capable */
        if (wol->wolopts) {
index ad76b8e35a00e188e39d00f4c5f70d97c3df5363..81d41539fcbab8e015d28e4b7729bc4812f60f0a 100644 (file)
@@ -2113,17 +2113,17 @@ static const struct net_device_ops macb_netdev_ops = {
 };
 
 #if defined(CONFIG_OF)
-static struct macb_config pc302gem_config = {
+static const struct macb_config pc302gem_config = {
        .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
        .dma_burst_length = 16,
 };
 
-static struct macb_config sama5d3_config = {
+static const struct macb_config sama5d3_config = {
        .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
        .dma_burst_length = 16,
 };
 
-static struct macb_config sama5d4_config = {
+static const struct macb_config sama5d4_config = {
        .caps = 0,
        .dma_burst_length = 4,
 };
@@ -2154,7 +2154,7 @@ static void macb_configure_caps(struct macb *bp)
        if (bp->pdev->dev.of_node) {
                match = of_match_node(macb_dt_ids, bp->pdev->dev.of_node);
                if (match && match->data) {
-                       config = (const struct macb_config *)match->data;
+                       config = match->data;
 
                        bp->caps = config->caps;
                        /*
index 31dc080f2437b6b02dde206b1e7c5343100fdde9..ff85619a97325fc0f1fa64a8896cbb8cc417d3cc 100644 (file)
 
 /* Bitfields in MID */
 #define MACB_IDNUM_OFFSET                      16
-#define MACB_IDNUM_SIZE                                16
+#define MACB_IDNUM_SIZE                                12
 #define MACB_REV_OFFSET                                0
 #define MACB_REV_SIZE                          16
 
index 9062a843424688beabaa21e46b3e210387658c81..c308429dd9c7fa0aebf2cee3b951f71f3863d939 100644 (file)
@@ -35,10 +35,10 @@ static inline unsigned int ipv6_clip_hash(struct clip_tbl *d, const u32 *key)
 }
 
 static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr,
-                                  int addr_len)
+                                  u8 v6)
 {
-       return addr_len == 4 ? ipv4_clip_hash(ctbl, addr) :
-                               ipv6_clip_hash(ctbl, addr);
+       return v6 ? ipv6_clip_hash(ctbl, addr) :
+                       ipv4_clip_hash(ctbl, addr);
 }
 
 static int clip6_get_mbox(const struct net_device *dev,
@@ -78,23 +78,22 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
        struct clip_entry *ce, *cte;
        u32 *addr = (u32 *)lip;
        int hash;
-       int addr_len;
-       int ret = 0;
+       int ret = -1;
 
        if (!ctbl)
                return 0;
 
-       if (v6)
-               addr_len = 16;
-       else
-               addr_len = 4;
-
-       hash = clip_addr_hash(ctbl, addr, addr_len);
+       hash = clip_addr_hash(ctbl, addr, v6);
 
        read_lock_bh(&ctbl->lock);
        list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
-               if (addr_len == cte->addr_len &&
-                   memcmp(lip, cte->addr, cte->addr_len) == 0) {
+               if (cte->addr6.sin6_family == AF_INET6 && v6)
+                       ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
+                                    sizeof(struct in6_addr));
+               else if (cte->addr.sin_family == AF_INET && !v6)
+                       ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
+                                    sizeof(struct in_addr));
+               if (!ret) {
                        ce = cte;
                        read_unlock_bh(&ctbl->lock);
                        goto found;
@@ -111,15 +110,20 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
                spin_lock_init(&ce->lock);
                atomic_set(&ce->refcnt, 0);
                atomic_dec(&ctbl->nfree);
-               ce->addr_len = addr_len;
-               memcpy(ce->addr, lip, addr_len);
                list_add_tail(&ce->list, &ctbl->hash_list[hash]);
                if (v6) {
+                       ce->addr6.sin6_family = AF_INET6;
+                       memcpy(ce->addr6.sin6_addr.s6_addr,
+                              lip, sizeof(struct in6_addr));
                        ret = clip6_get_mbox(dev, (const struct in6_addr *)lip);
                        if (ret) {
                                write_unlock_bh(&ctbl->lock);
                                return ret;
                        }
+               } else {
+                       ce->addr.sin_family = AF_INET;
+                       memcpy((char *)(&ce->addr.sin_addr), lip,
+                              sizeof(struct in_addr));
                }
        } else {
                write_unlock_bh(&ctbl->lock);
@@ -140,19 +144,19 @@ void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
        struct clip_entry *ce, *cte;
        u32 *addr = (u32 *)lip;
        int hash;
-       int addr_len;
-
-       if (v6)
-               addr_len = 16;
-       else
-               addr_len = 4;
+       int ret = -1;
 
-       hash = clip_addr_hash(ctbl, addr, addr_len);
+       hash = clip_addr_hash(ctbl, addr, v6);
 
        read_lock_bh(&ctbl->lock);
        list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
-               if (addr_len == cte->addr_len &&
-                   memcmp(lip, cte->addr, cte->addr_len) == 0) {
+               if (cte->addr6.sin6_family == AF_INET6 && v6)
+                       ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
+                                    sizeof(struct in6_addr));
+               else if (cte->addr.sin_family == AF_INET && !v6)
+                       ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
+                                    sizeof(struct in_addr));
+               if (!ret) {
                        ce = cte;
                        read_unlock_bh(&ctbl->lock);
                        goto found;
@@ -249,10 +253,7 @@ int clip_tbl_show(struct seq_file *seq, void *v)
        for (i = 0 ; i < ctbl->clipt_size;  ++i) {
                list_for_each_entry(ce, &ctbl->hash_list[i], list) {
                        ip[0] = '\0';
-                       if (ce->addr_len == 16)
-                               sprintf(ip, "%pI6c", ce->addr);
-                       else
-                               sprintf(ip, "%pI4c", ce->addr);
+                       sprintf(ip, "%pISc", &ce->addr);
                        seq_printf(seq, "%-25s   %u\n", ip,
                                   atomic_read(&ce->refcnt));
                }
index 2eaba0161cf8104eb8cbf9756112174fd1275b38..35eb43c6bcbbe37e5f934a767154bc4f4fe2f5c7 100644 (file)
@@ -14,8 +14,10 @@ struct clip_entry {
        spinlock_t lock;        /* Hold while modifying clip reference */
        atomic_t refcnt;
        struct list_head list;
-       u32 addr[4];
-       int addr_len;
+       union {
+               struct sockaddr_in addr;
+               struct sockaddr_in6 addr6;
+       };
 };
 
 struct clip_tbl {
index d6cda17efe6ef475a5579d8248e01a3158bbc272..c6ff4890d171a1509c7b3ca2aa21e5b0edd6039f 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 78854ceb0870a29004ab04261fa26b296b958d4e..dcb0479452907abd43732aa9332f927f7f0c3ef3 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 a22cf932ca3536920798ef50241fd9b43c26857a..d92995138f7ef9253c3b2ac37efba2c491e2f528 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 b4b9f6048fe730dc1287a648a5e61c7f2d92dd7d..b688b32c21fe530aa0cd48b61323bca3ed269b53 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 4d643b65265e8ee0ad12ed886cbb2b77b9d2557b..ee394dc68303851153a3598fe4455cec972597d9 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 231a725f6d5d1679c4d6b07ff6694ac387f0b66a..326674b19983825af5631993b4427e0132ed6ba6 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 9b353a88cbdab13a7ce85456e393edf197dd1740..a4a19e0ec7f5d76590f0e73641d5e03afbcde43a 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 e2bd3f74785851d0db24c282f5a497972bcaf20f..b9d1cbac0eee3c97e76cff147df732601b83f714 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 0545f0de1c52be282af53d6a5f03916f93ad7013..e0d711071afb7d6d80763666141477fb3dc4c479 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 1b5506df35b15ab74eaf1ecea220da4ad6278a3f..280b4a21584934f56fbcc24399dfd0cf5feb694e 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 9cbe038a388ea62a6f4552e7f088dc5816dc5b5c..a5179bfcdc2c1b6124a92f33f9c5f57363751a02 100644 (file)
@@ -272,8 +272,8 @@ static irqreturn_t enic_isr_legacy(int irq, void *data)
        }
 
        if (ENIC_TEST_INTR(pba, notify_intr)) {
-               vnic_intr_return_all_credits(&enic->intr[notify_intr]);
                enic_notify_check(enic);
+               vnic_intr_return_all_credits(&enic->intr[notify_intr]);
        }
 
        if (ENIC_TEST_INTR(pba, err_intr)) {
@@ -346,8 +346,8 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data)
        struct enic *enic = data;
        unsigned int intr = enic_msix_notify_intr(enic);
 
-       vnic_intr_return_all_credits(&enic->intr[intr]);
        enic_notify_check(enic);
+       vnic_intr_return_all_credits(&enic->intr[intr]);
 
        return IRQ_HANDLED;
 }
index 3b42556f7f8d66929f1435445df06072c65ae6aa..ed41559bae771b8d58e49f21a46f7a79d9f20cac 100644 (file)
@@ -589,7 +589,7 @@ static void tulip_tx_timeout(struct net_device *dev)
                               (unsigned int)tp->rx_ring[i].buffer1,
                               (unsigned int)tp->rx_ring[i].buffer2,
                               buf[0], buf[1], buf[2]);
-                       for (j = 0; buf[j] != 0xee && j < 1600; j++)
+                       for (j = 0; ((j < 1600) && buf[j] != 0xee); j++)
                                if (j < 100)
                                        pr_cont(" %02x", buf[j]);
                        pr_cont(" j=%d\n", j);
index 27de37aa90afe12b2d564d87c9b13246160d39aa..27b9fe99a9bdfa4eddb70aaa9749eaef6bdd3518 100644 (file)
@@ -354,6 +354,7 @@ struct be_vf_cfg {
        u16 vlan_tag;
        u32 tx_rate;
        u32 plink_tracking;
+       u32 privileges;
 };
 
 enum vf_state {
@@ -423,6 +424,7 @@ struct be_adapter {
 
        u8 __iomem *csr;        /* CSR BAR used only for BE2/3 */
        u8 __iomem *db;         /* Door Bell */
+       u8 __iomem *pcicfg;     /* On SH,BEx only. Shadow of PCI config space */
 
        struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
        struct be_dma_mem mbox_mem;
index 36916cfa70f9a7d31f36b7d80135e61f854a499a..7f05f309e93596778851fb280fa4c8bd068828c3 100644 (file)
@@ -1902,15 +1902,11 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
 {
        int num_eqs, i = 0;
 
-       if (lancer_chip(adapter) && num > 8) {
-               while (num) {
-                       num_eqs = min(num, 8);
-                       __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
-                       i += num_eqs;
-                       num -= num_eqs;
-               }
-       } else {
-               __be_cmd_modify_eqd(adapter, set_eqd, num);
+       while (num) {
+               num_eqs = min(num, 8);
+               __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
+               i += num_eqs;
+               num -= num_eqs;
        }
 
        return 0;
@@ -1918,7 +1914,7 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
 
 /* Uses sycnhronous mcc */
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num)
+                      u32 num, u32 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_vlan_config *req;
@@ -1936,6 +1932,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
        be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                               OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req),
                               wrb, NULL);
+       req->hdr.domain = domain;
 
        req->interface_id = if_id;
        req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0;
index db761e8e42a3224486ced01238f9fb6b61ad3579..a7634a3f052ac02786baa7e63e764d86262720a9 100644 (file)
@@ -2256,7 +2256,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
 int be_cmd_get_fw_ver(struct be_adapter *adapter);
 int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num);
 int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
-                      u32 num);
+                      u32 num, u32 domain);
 int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
 int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc);
 int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc);
index 0a816859aca507c3e762aeebbf6d0601e3529aec..e6b790f0d9dc1ebfe6103a1549e84cf058522027 100644 (file)
@@ -1171,7 +1171,7 @@ static int be_vid_config(struct be_adapter *adapter)
        for_each_set_bit(i, adapter->vids, VLAN_N_VID)
                vids[num++] = cpu_to_le16(i);
 
-       status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num);
+       status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num, 0);
        if (status) {
                dev_err(dev, "Setting HW VLAN filtering failed\n");
                /* Set to VLAN promisc mode as setting VLAN filter failed */
@@ -1380,11 +1380,67 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
        return 0;
 }
 
+static int be_set_vf_tvt(struct be_adapter *adapter, int vf, u16 vlan)
+{
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+       u16 vids[BE_NUM_VLANS_SUPPORTED];
+       int vf_if_id = vf_cfg->if_handle;
+       int status;
+
+       /* Enable Transparent VLAN Tagging */
+       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, vf_if_id, 0);
+       if (status)
+               return status;
+
+       /* Clear pre-programmed VLAN filters on VF if any, if TVT is enabled */
+       vids[0] = 0;
+       status = be_cmd_vlan_config(adapter, vf_if_id, vids, 1, vf + 1);
+       if (!status)
+               dev_info(&adapter->pdev->dev,
+                        "Cleared guest VLANs on VF%d", vf);
+
+       /* After TVT is enabled, disallow VFs to program VLAN filters */
+       if (vf_cfg->privileges & BE_PRIV_FILTMGMT) {
+               status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges &
+                                                 ~BE_PRIV_FILTMGMT, vf + 1);
+               if (!status)
+                       vf_cfg->privileges &= ~BE_PRIV_FILTMGMT;
+       }
+       return 0;
+}
+
+static int be_clear_vf_tvt(struct be_adapter *adapter, int vf)
+{
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+       struct device *dev = &adapter->pdev->dev;
+       int status;
+
+       /* Reset Transparent VLAN Tagging. */
+       status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID, vf + 1,
+                                      vf_cfg->if_handle, 0);
+       if (status)
+               return status;
+
+       /* Allow VFs to program VLAN filtering */
+       if (!(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
+               status = be_cmd_set_fn_privileges(adapter, vf_cfg->privileges |
+                                                 BE_PRIV_FILTMGMT, vf + 1);
+               if (!status) {
+                       vf_cfg->privileges |= BE_PRIV_FILTMGMT;
+                       dev_info(dev, "VF%d: FILTMGMT priv enabled", vf);
+               }
+       }
+
+       dev_info(dev,
+                "Disable/re-enable i/f in VM to clear Transparent VLAN tag");
+       return 0;
+}
+
 static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
-       int status = 0;
+       int status;
 
        if (!sriov_enabled(adapter))
                return -EPERM;
@@ -1394,24 +1450,19 @@ static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
 
        if (vlan || qos) {
                vlan |= qos << VLAN_PRIO_SHIFT;
-               if (vf_cfg->vlan_tag != vlan)
-                       status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                                                      vf_cfg->if_handle, 0);
+               status = be_set_vf_tvt(adapter, vf, vlan);
        } else {
-               /* Reset Transparent Vlan Tagging. */
-               status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
-                                              vf + 1, vf_cfg->if_handle, 0);
+               status = be_clear_vf_tvt(adapter, vf);
        }
 
        if (status) {
                dev_err(&adapter->pdev->dev,
-                       "VLAN %d config on VF %d failed : %#x\n", vlan,
-                       vf, status);
+                       "VLAN %d config on VF %d failed : %#x\n", vlan, vf,
+                       status);
                return be_cmd_status(status);
        }
 
        vf_cfg->vlan_tag = vlan;
-
        return 0;
 }
 
@@ -2772,14 +2823,12 @@ void be_detect_error(struct be_adapter *adapter)
                        }
                }
        } else {
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_LOW, &ue_lo);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_HIGH, &ue_hi);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_LOW_MASK, &ue_lo_mask);
-               pci_read_config_dword(adapter->pdev,
-                                     PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask);
+               ue_lo = ioread32(adapter->pcicfg + PCICFG_UE_STATUS_LOW);
+               ue_hi = ioread32(adapter->pcicfg + PCICFG_UE_STATUS_HIGH);
+               ue_lo_mask = ioread32(adapter->pcicfg +
+                                     PCICFG_UE_STATUS_LOW_MASK);
+               ue_hi_mask = ioread32(adapter->pcicfg +
+                                     PCICFG_UE_STATUS_HI_MASK);
 
                ue_lo = (ue_lo & ~ue_lo_mask);
                ue_hi = (ue_hi & ~ue_hi_mask);
@@ -3339,7 +3388,6 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
                        u32 cap_flags, u32 vf)
 {
        u32 en_flags;
-       int status;
 
        en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                   BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
@@ -3347,10 +3395,7 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
 
        en_flags &= cap_flags;
 
-       status = be_cmd_if_create(adapter, cap_flags, en_flags,
-                                 if_handle, vf);
-
-       return status;
+       return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
 }
 
 static int be_vfs_if_create(struct be_adapter *adapter)
@@ -3368,8 +3413,13 @@ static int be_vfs_if_create(struct be_adapter *adapter)
                if (!BE3_chip(adapter)) {
                        status = be_cmd_get_profile_config(adapter, &res,
                                                           vf + 1);
-                       if (!status)
+                       if (!status) {
                                cap_flags = res.if_cap_flags;
+                               /* Prevent VFs from enabling VLAN promiscuous
+                                * mode
+                                */
+                               cap_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS;
+                       }
                }
 
                status = be_if_create(adapter, &vf_cfg->if_handle,
@@ -3403,7 +3453,6 @@ static int be_vf_setup(struct be_adapter *adapter)
        struct device *dev = &adapter->pdev->dev;
        struct be_vf_cfg *vf_cfg;
        int status, old_vfs, vf;
-       u32 privileges;
 
        old_vfs = pci_num_vf(adapter->pdev);
 
@@ -3433,15 +3482,18 @@ static int be_vf_setup(struct be_adapter *adapter)
 
        for_all_vfs(adapter, vf_cfg, vf) {
                /* Allow VFs to programs MAC/VLAN filters */
-               status = be_cmd_get_fn_privileges(adapter, &privileges, vf + 1);
-               if (!status && !(privileges & BE_PRIV_FILTMGMT)) {
+               status = be_cmd_get_fn_privileges(adapter, &vf_cfg->privileges,
+                                                 vf + 1);
+               if (!status && !(vf_cfg->privileges & BE_PRIV_FILTMGMT)) {
                        status = be_cmd_set_fn_privileges(adapter,
-                                                         privileges |
+                                                         vf_cfg->privileges |
                                                          BE_PRIV_FILTMGMT,
                                                          vf + 1);
-                       if (!status)
+                       if (!status) {
+                               vf_cfg->privileges |= BE_PRIV_FILTMGMT;
                                dev_info(dev, "VF%d has FILTMGMT privilege\n",
                                         vf);
+                       }
                }
 
                /* Allow full available bandwidth */
@@ -4820,24 +4872,37 @@ static int be_roce_map_pci_bars(struct be_adapter *adapter)
 
 static int be_map_pci_bars(struct be_adapter *adapter)
 {
+       struct pci_dev *pdev = adapter->pdev;
        u8 __iomem *addr;
 
        if (BEx_chip(adapter) && be_physfn(adapter)) {
-               adapter->csr = pci_iomap(adapter->pdev, 2, 0);
+               adapter->csr = pci_iomap(pdev, 2, 0);
                if (!adapter->csr)
                        return -ENOMEM;
        }
 
-       addr = pci_iomap(adapter->pdev, db_bar(adapter), 0);
+       addr = pci_iomap(pdev, db_bar(adapter), 0);
        if (!addr)
                goto pci_map_err;
        adapter->db = addr;
 
+       if (skyhawk_chip(adapter) || BEx_chip(adapter)) {
+               if (be_physfn(adapter)) {
+                       /* PCICFG is the 2nd BAR in BE2 */
+                       addr = pci_iomap(pdev, BE2_chip(adapter) ? 1 : 0, 0);
+                       if (!addr)
+                               goto pci_map_err;
+                       adapter->pcicfg = addr;
+               } else {
+                       adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
+               }
+       }
+
        be_roce_map_pci_bars(adapter);
        return 0;
 
 pci_map_err:
-       dev_err(&adapter->pdev->dev, "Error in mapping PCI BARs\n");
+       dev_err(&pdev->dev, "Error in mapping PCI BARs\n");
        be_unmap_pci_bars(adapter);
        return -ENOMEM;
 }
index 9bb6220663b21a505f2332f028ce3a1e13b77f86..f6a3a7abd468e1f25fd4c33e874a38f0c85bc4dd 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 43df78882e484e065706bd04c322fa8276d4c424..7bf3682cdf478b1597cf04e071b525eed31adb69 100644 (file)
@@ -747,6 +747,18 @@ static int gfar_parse_group(struct device_node *np,
        return 0;
 }
 
+static int gfar_of_group_count(struct device_node *np)
+{
+       struct device_node *child;
+       int num = 0;
+
+       for_each_available_child_of_node(np, child)
+               if (!of_node_cmp(child->name, "queue-group"))
+                       num++;
+
+       return num;
+}
+
 static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 {
        const char *model;
@@ -784,7 +796,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                num_rx_qs = 1;
        } else { /* MQ_MG_MODE */
                /* get the actual number of supported groups */
-               unsigned int num_grps = of_get_available_child_count(np);
+               unsigned int num_grps = gfar_of_group_count(np);
 
                if (num_grps == 0 || num_grps > MAXGROUPS) {
                        dev_err(&ofdev->dev, "Invalid # of int groups(%d)\n",
@@ -851,7 +863,10 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 
        /* Parse and initialize group specific information */
        if (priv->mode == MQ_MG_MODE) {
-               for_each_child_of_node(np, child) {
+               for_each_available_child_of_node(np, child) {
+                       if (of_node_cmp(child->name, "queue-group"))
+                               continue;
+
                        err = gfar_parse_group(child, priv, model);
                        if (err)
                                goto err_grp_init;
@@ -3162,8 +3177,8 @@ static void adjust_link(struct net_device *dev)
        struct phy_device *phydev = priv->phydev;
 
        if (unlikely(phydev->link != priv->oldlink ||
-                    phydev->duplex != priv->oldduplex ||
-                    phydev->speed != priv->oldspeed))
+                    (phydev->link && (phydev->duplex != priv->oldduplex ||
+                                      phydev->speed != priv->oldspeed))))
                gfar_update_link_state(priv);
 }
 
index 357e8b576905a4a61c312e6c9736c087b706b69d..56b774d3a13d4c3856ad01fff0ebe67c128e4f65 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 e8a1adb7a96255bf8da1baa87b29514527c2764d..c05e50759621137fa3f9749a55c347381d54ed55 100644 (file)
@@ -3262,6 +3262,139 @@ static void ehea_remove_device_sysfs(struct platform_device *dev)
        device_remove_file(&dev->dev, &dev_attr_remove_port);
 }
 
+static int ehea_reboot_notifier(struct notifier_block *nb,
+                               unsigned long action, void *unused)
+{
+       if (action == SYS_RESTART) {
+               pr_info("Reboot: freeing all eHEA resources\n");
+               ibmebus_unregister_driver(&ehea_driver);
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block ehea_reboot_nb = {
+       .notifier_call = ehea_reboot_notifier,
+};
+
+static int ehea_mem_notifier(struct notifier_block *nb,
+                            unsigned long action, void *data)
+{
+       int ret = NOTIFY_BAD;
+       struct memory_notify *arg = data;
+
+       mutex_lock(&dlpar_mem_lock);
+
+       switch (action) {
+       case MEM_CANCEL_OFFLINE:
+               pr_info("memory offlining canceled");
+               /* Fall through: re-add canceled memory block */
+
+       case MEM_ONLINE:
+               pr_info("memory is going online");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
+               if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
+                       goto out_unlock;
+               ehea_rereg_mrs();
+               break;
+
+       case MEM_GOING_OFFLINE:
+               pr_info("memory is going offline");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
+               if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
+                       goto out_unlock;
+               ehea_rereg_mrs();
+               break;
+
+       default:
+               break;
+       }
+
+       ehea_update_firmware_handles();
+       ret = NOTIFY_OK;
+
+out_unlock:
+       mutex_unlock(&dlpar_mem_lock);
+       return ret;
+}
+
+static struct notifier_block ehea_mem_nb = {
+       .notifier_call = ehea_mem_notifier,
+};
+
+static void ehea_crash_handler(void)
+{
+       int i;
+
+       if (ehea_fw_handles.arr)
+               for (i = 0; i < ehea_fw_handles.num_entries; i++)
+                       ehea_h_free_resource(ehea_fw_handles.arr[i].adh,
+                                            ehea_fw_handles.arr[i].fwh,
+                                            FORCE_FREE);
+
+       if (ehea_bcmc_regs.arr)
+               for (i = 0; i < ehea_bcmc_regs.num_entries; i++)
+                       ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh,
+                                             ehea_bcmc_regs.arr[i].port_id,
+                                             ehea_bcmc_regs.arr[i].reg_type,
+                                             ehea_bcmc_regs.arr[i].macaddr,
+                                             0, H_DEREG_BCMC);
+}
+
+static atomic_t ehea_memory_hooks_registered;
+
+/* Register memory hooks on probe of first adapter */
+static int ehea_register_memory_hooks(void)
+{
+       int ret = 0;
+
+       if (atomic_inc_and_test(&ehea_memory_hooks_registered))
+               return 0;
+
+       ret = ehea_create_busmap();
+       if (ret) {
+               pr_info("ehea_create_busmap failed\n");
+               goto out;
+       }
+
+       ret = register_reboot_notifier(&ehea_reboot_nb);
+       if (ret) {
+               pr_info("register_reboot_notifier failed\n");
+               goto out;
+       }
+
+       ret = register_memory_notifier(&ehea_mem_nb);
+       if (ret) {
+               pr_info("register_memory_notifier failed\n");
+               goto out2;
+       }
+
+       ret = crash_shutdown_register(ehea_crash_handler);
+       if (ret) {
+               pr_info("crash_shutdown_register failed\n");
+               goto out3;
+       }
+
+       return 0;
+
+out3:
+       unregister_memory_notifier(&ehea_mem_nb);
+out2:
+       unregister_reboot_notifier(&ehea_reboot_nb);
+out:
+       return ret;
+}
+
+static void ehea_unregister_memory_hooks(void)
+{
+       if (atomic_read(&ehea_memory_hooks_registered))
+               return;
+
+       unregister_reboot_notifier(&ehea_reboot_nb);
+       if (crash_shutdown_unregister(ehea_crash_handler))
+               pr_info("failed unregistering crash handler\n");
+       unregister_memory_notifier(&ehea_mem_nb);
+}
+
 static int ehea_probe_adapter(struct platform_device *dev)
 {
        struct ehea_adapter *adapter;
@@ -3269,6 +3402,10 @@ static int ehea_probe_adapter(struct platform_device *dev)
        int ret;
        int i;
 
+       ret = ehea_register_memory_hooks();
+       if (ret)
+               return ret;
+
        if (!dev || !dev->dev.of_node) {
                pr_err("Invalid ibmebus device probed\n");
                return -EINVAL;
@@ -3392,81 +3529,6 @@ static int ehea_remove(struct platform_device *dev)
        return 0;
 }
 
-static void ehea_crash_handler(void)
-{
-       int i;
-
-       if (ehea_fw_handles.arr)
-               for (i = 0; i < ehea_fw_handles.num_entries; i++)
-                       ehea_h_free_resource(ehea_fw_handles.arr[i].adh,
-                                            ehea_fw_handles.arr[i].fwh,
-                                            FORCE_FREE);
-
-       if (ehea_bcmc_regs.arr)
-               for (i = 0; i < ehea_bcmc_regs.num_entries; i++)
-                       ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh,
-                                             ehea_bcmc_regs.arr[i].port_id,
-                                             ehea_bcmc_regs.arr[i].reg_type,
-                                             ehea_bcmc_regs.arr[i].macaddr,
-                                             0, H_DEREG_BCMC);
-}
-
-static int ehea_mem_notifier(struct notifier_block *nb,
-                             unsigned long action, void *data)
-{
-       int ret = NOTIFY_BAD;
-       struct memory_notify *arg = data;
-
-       mutex_lock(&dlpar_mem_lock);
-
-       switch (action) {
-       case MEM_CANCEL_OFFLINE:
-               pr_info("memory offlining canceled");
-               /* Readd canceled memory block */
-       case MEM_ONLINE:
-               pr_info("memory is going online");
-               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
-               if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
-                       goto out_unlock;
-               ehea_rereg_mrs();
-               break;
-       case MEM_GOING_OFFLINE:
-               pr_info("memory is going offline");
-               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
-               if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
-                       goto out_unlock;
-               ehea_rereg_mrs();
-               break;
-       default:
-               break;
-       }
-
-       ehea_update_firmware_handles();
-       ret = NOTIFY_OK;
-
-out_unlock:
-       mutex_unlock(&dlpar_mem_lock);
-       return ret;
-}
-
-static struct notifier_block ehea_mem_nb = {
-       .notifier_call = ehea_mem_notifier,
-};
-
-static int ehea_reboot_notifier(struct notifier_block *nb,
-                               unsigned long action, void *unused)
-{
-       if (action == SYS_RESTART) {
-               pr_info("Reboot: freeing all eHEA resources\n");
-               ibmebus_unregister_driver(&ehea_driver);
-       }
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block ehea_reboot_nb = {
-       .notifier_call = ehea_reboot_notifier,
-};
-
 static int check_module_parm(void)
 {
        int ret = 0;
@@ -3520,26 +3582,10 @@ static int __init ehea_module_init(void)
        if (ret)
                goto out;
 
-       ret = ehea_create_busmap();
-       if (ret)
-               goto out;
-
-       ret = register_reboot_notifier(&ehea_reboot_nb);
-       if (ret)
-               pr_info("failed registering reboot notifier\n");
-
-       ret = register_memory_notifier(&ehea_mem_nb);
-       if (ret)
-               pr_info("failed registering memory remove notifier\n");
-
-       ret = crash_shutdown_register(ehea_crash_handler);
-       if (ret)
-               pr_info("failed registering crash handler\n");
-
        ret = ibmebus_register_driver(&ehea_driver);
        if (ret) {
                pr_err("failed registering eHEA device driver on ebus\n");
-               goto out2;
+               goto out;
        }
 
        ret = driver_create_file(&ehea_driver.driver,
@@ -3547,32 +3593,22 @@ static int __init ehea_module_init(void)
        if (ret) {
                pr_err("failed to register capabilities attribute, ret=%d\n",
                       ret);
-               goto out3;
+               goto out2;
        }
 
        return ret;
 
-out3:
-       ibmebus_unregister_driver(&ehea_driver);
 out2:
-       unregister_memory_notifier(&ehea_mem_nb);
-       unregister_reboot_notifier(&ehea_reboot_nb);
-       crash_shutdown_unregister(ehea_crash_handler);
+       ibmebus_unregister_driver(&ehea_driver);
 out:
        return ret;
 }
 
 static void __exit ehea_module_exit(void)
 {
-       int ret;
-
        driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
        ibmebus_unregister_driver(&ehea_driver);
-       unregister_reboot_notifier(&ehea_reboot_nb);
-       ret = crash_shutdown_unregister(ehea_crash_handler);
-       if (ret)
-               pr_info("failed unregistering crash handler\n");
-       unregister_memory_notifier(&ehea_mem_nb);
+       ehea_unregister_memory_hooks();
        kfree(ehea_fw_handles.arr);
        kfree(ehea_bcmc_regs.arr);
        ehea_destroy_busmap();
index 21978cc019e7c86dab83968ba994c0e9051c8e33..cd7675ac5bf9ed8b8658996d2d27190c6b20245f 100644 (file)
@@ -1136,6 +1136,8 @@ restart_poll:
        ibmveth_replenish_task(adapter);
 
        if (frames_processed < budget) {
+               napi_complete(napi);
+
                /* We think we are done - reenable interrupts,
                 * then check once more to make sure we are done.
                 */
@@ -1144,8 +1146,6 @@ restart_poll:
 
                BUG_ON(lpar_rc != H_SUCCESS);
 
-               napi_complete(napi);
-
                if (ibmveth_rxq_pending_buffer(adapter) &&
                    napi_reschedule(napi)) {
                        lpar_rc = h_vio_signal(adapter->vdev->unit_address,
@@ -1327,6 +1327,28 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
        return ret;
 }
 
+static int ibmveth_set_mac_addr(struct net_device *dev, void *p)
+{
+       struct ibmveth_adapter *adapter = netdev_priv(dev);
+       struct sockaddr *addr = p;
+       u64 mac_address;
+       int rc;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       mac_address = ibmveth_encode_mac_addr(addr->sa_data);
+       rc = h_change_logical_lan_mac(adapter->vdev->unit_address, mac_address);
+       if (rc) {
+               netdev_err(adapter->netdev, "h_change_logical_lan_mac failed with rc=%d\n", rc);
+               return rc;
+       }
+
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
+
+       return 0;
+}
+
 static const struct net_device_ops ibmveth_netdev_ops = {
        .ndo_open               = ibmveth_open,
        .ndo_stop               = ibmveth_close,
@@ -1337,7 +1359,7 @@ static const struct net_device_ops ibmveth_netdev_ops = {
        .ndo_fix_features       = ibmveth_fix_features,
        .ndo_set_features       = ibmveth_set_features,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = ibmveth_set_mac_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ibmveth_poll_controller,
 #endif
index 11a9ffebf8d88acdfd5b738baab62bd2b34aa30a..6aea65dae5ed654b5da2e7a8885a02a92c75710d 100644 (file)
@@ -868,8 +868,9 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw)
         * The grst delay value is in 100ms units, and we'll wait a
         * couple counts longer to be sure we don't just miss the end.
         */
-       grst_del = rd32(hw, I40E_GLGEN_RSTCTL) & I40E_GLGEN_RSTCTL_GRSTDEL_MASK
-                       >> I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
+       grst_del = (rd32(hw, I40E_GLGEN_RSTCTL) &
+                   I40E_GLGEN_RSTCTL_GRSTDEL_MASK) >>
+                   I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
        for (cnt = 0; cnt < grst_del + 2; cnt++) {
                reg = rd32(hw, I40E_GLGEN_RSTAT);
                if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
@@ -2846,7 +2847,7 @@ i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
 
        status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
 
-       if (!status)
+       if (!status && filter_index)
                *filter_index = resp->index;
 
        return status;
index 183dcb63ce98e14e5b504bed9874911b35ae18d3..a11c70ca5a2811c84cc094ac425b93ec0b840d5d 100644 (file)
@@ -40,7 +40,7 @@ static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
        u32 val;
 
        val = rd32(hw, I40E_PRTDCB_GENC);
-       *delay = (u16)(val & I40E_PRTDCB_GENC_PFCLDA_MASK >>
+       *delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >>
                       I40E_PRTDCB_GENC_PFCLDA_SHIFT);
 }
 
index 61236f983971a1d55955586cd5a6ee288f5c60e7..c17ee77100d3651e254265ae192bd4d3e54c3659 100644 (file)
@@ -989,8 +989,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
        if (!cmd_buf)
                return count;
        bytes_not_copied = copy_from_user(cmd_buf, buffer, count);
-       if (bytes_not_copied < 0)
+       if (bytes_not_copied < 0) {
+               kfree(cmd_buf);
                return bytes_not_copied;
+       }
        if (bytes_not_copied > 0)
                count -= bytes_not_copied;
        cmd_buf[count] = '\0';
index cbe281be1c9f0c1956c4e7d2467b42474fad70c2..dadda3c5d658b950cf64d21c838f5ffd5176f0f6 100644 (file)
@@ -1512,7 +1512,12 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
        vsi->tc_config.numtc = numtc;
        vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1;
        /* Number of queues per enabled TC */
-       num_tc_qps = vsi->alloc_queue_pairs/numtc;
+       /* In MFP case we can have a much lower count of MSIx
+        * vectors available and so we need to lower the used
+        * q count.
+        */
+       qcount = min_t(int, vsi->alloc_queue_pairs, pf->num_lan_msix);
+       num_tc_qps = qcount / numtc;
        num_tc_qps = min_t(int, num_tc_qps, I40E_MAX_QUEUES_PER_TC);
 
        /* Setup queue offset/count for all TCs for given VSI */
@@ -2684,8 +2689,15 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi)
        u16 qoffset, qcount;
        int i, n;
 
-       if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED))
-               return;
+       if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
+               /* Reset the TC information */
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       rx_ring = vsi->rx_rings[i];
+                       tx_ring = vsi->tx_rings[i];
+                       rx_ring->dcb_tc = 0;
+                       tx_ring->dcb_tc = 0;
+               }
+       }
 
        for (n = 0; n < I40E_MAX_TRAFFIC_CLASS; n++) {
                if (!(vsi->tc_config.enabled_tc & (1 << n)))
@@ -3830,6 +3842,12 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
 {
        int i;
 
+       i40e_stop_misc_vector(pf);
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               synchronize_irq(pf->msix_entries[0].vector);
+               free_irq(pf->msix_entries[0].vector, pf);
+       }
+
        i40e_put_lump(pf->irq_pile, 0, I40E_PILE_VALID_BIT-1);
        for (i = 0; i < pf->num_alloc_vsi; i++)
                if (pf->vsi[i])
@@ -5254,8 +5272,14 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
 
        /* Wait for the PF's Tx queues to be disabled */
        ret = i40e_pf_wait_txq_disabled(pf);
-       if (!ret)
+       if (ret) {
+               /* Schedule PF reset to recover */
+               set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
+               i40e_service_event_schedule(pf);
+       } else {
                i40e_pf_unquiesce_all_vsi(pf);
+       }
+
 exit:
        return ret;
 }
@@ -5587,7 +5611,8 @@ static void i40e_check_hang_subtask(struct i40e_pf *pf)
        int i, v;
 
        /* If we're down or resetting, just bail */
-       if (test_bit(__I40E_CONFIG_BUSY, &pf->state))
+       if (test_bit(__I40E_DOWN, &pf->state) ||
+           test_bit(__I40E_CONFIG_BUSY, &pf->state))
                return;
 
        /* for each VSI/netdev
@@ -9533,6 +9558,7 @@ static void i40e_remove(struct pci_dev *pdev)
        set_bit(__I40E_DOWN, &pf->state);
        del_timer_sync(&pf->service_timer);
        cancel_work_sync(&pf->service_task);
+       i40e_fdir_teardown(pf);
 
        if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
                i40e_free_vfs(pf);
@@ -9559,12 +9585,6 @@ static void i40e_remove(struct pci_dev *pdev)
        if (pf->vsi[pf->lan_vsi])
                i40e_vsi_release(pf->vsi[pf->lan_vsi]);
 
-       i40e_stop_misc_vector(pf);
-       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
-               synchronize_irq(pf->msix_entries[0].vector);
-               free_irq(pf->msix_entries[0].vector, pf);
-       }
-
        /* shutdown and destroy the HMC */
        if (pf->hw.hmc.hmc_obj) {
                ret_code = i40e_shutdown_lan_hmc(&pf->hw);
@@ -9718,6 +9738,8 @@ static void i40e_shutdown(struct pci_dev *pdev)
        wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
        wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
 
+       i40e_clear_interrupt_scheme(pf);
+
        if (system_state == SYSTEM_POWER_OFF) {
                pci_wake_from_d3(pdev, pf->wol_en);
                pci_set_power_state(pdev, PCI_D3hot);
index 3e70f2e45a4768986a0a90ee21bdf98790db9b53..5defe0d635141ed5c886cb1086995f2b2d3d31a1 100644 (file)
@@ -679,9 +679,11 @@ static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
 {
        i40e_status status;
        enum i40e_nvmupd_cmd upd_cmd;
+       bool retry_attempt = false;
 
        upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno);
 
+retry:
        switch (upd_cmd) {
        case I40E_NVMUPD_WRITE_CON:
                status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno);
@@ -725,6 +727,39 @@ static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw,
                *errno = -ESRCH;
                break;
        }
+
+       /* In some circumstances, a multi-write transaction takes longer
+        * than the default 3 minute timeout on the write semaphore.  If
+        * the write failed with an EBUSY status, this is likely the problem,
+        * so here we try to reacquire the semaphore then retry the write.
+        * We only do one retry, then give up.
+        */
+       if (status && (hw->aq.asq_last_status == I40E_AQ_RC_EBUSY) &&
+           !retry_attempt) {
+               i40e_status old_status = status;
+               u32 old_asq_status = hw->aq.asq_last_status;
+               u32 gtime;
+
+               gtime = rd32(hw, I40E_GLVFGEN_TIMER);
+               if (gtime >= hw->nvm.hw_semaphore_timeout) {
+                       i40e_debug(hw, I40E_DEBUG_ALL,
+                                  "NVMUPD: write semaphore expired (%d >= %lld), retrying\n",
+                                  gtime, hw->nvm.hw_semaphore_timeout);
+                       i40e_release_nvm(hw);
+                       status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
+                       if (status) {
+                               i40e_debug(hw, I40E_DEBUG_ALL,
+                                          "NVMUPD: write semaphore reacquire failed aq_err = %d\n",
+                                          hw->aq.asq_last_status);
+                               status = old_status;
+                               hw->aq.asq_last_status = old_asq_status;
+                       } else {
+                               retry_attempt = true;
+                               goto retry;
+                       }
+               }
+       }
+
        return status;
 }
 
index 2206d2d36f0fdf2e9f249c7624e156f8c1b17118..bbf1b1247ac471bb712ed1397956db83cf80e4f3 100644 (file)
@@ -585,6 +585,20 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
        }
 }
 
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring:  tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+       return le32_to_cpu(*(volatile __le32 *)head);
+}
+
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
  * @tx_ring: the ring of descriptors
@@ -594,10 +608,16 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
  **/
 static u32 i40e_get_tx_pending(struct i40e_ring *ring)
 {
-       u32 ntu = ((ring->next_to_clean <= ring->next_to_use)
-                       ? ring->next_to_use
-                       : ring->next_to_use + ring->count);
-       return ntu - ring->next_to_clean;
+       u32 head, tail;
+
+       head = i40e_get_head(ring);
+       tail = readl(ring->tail);
+
+       if (head != tail)
+               return (head < tail) ?
+                       tail - head : (tail + ring->count - head);
+
+       return 0;
 }
 
 /**
@@ -606,6 +626,8 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
  **/
 static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
 {
+       u32 tx_done = tx_ring->stats.packets;
+       u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
        u32 tx_pending = i40e_get_tx_pending(tx_ring);
        struct i40e_pf *pf = tx_ring->vsi->back;
        bool ret = false;
@@ -623,41 +645,25 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * run the check_tx_hang logic with a transmit completion
         * pending but without time to complete it yet.
         */
-       if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           (tx_pending >= I40E_MIN_DESC_PENDING)) {
+       if ((tx_done_old == tx_done) && tx_pending) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
-       } else if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-                  (tx_pending < I40E_MIN_DESC_PENDING) &&
-                  (tx_pending > 0)) {
+       } else if (tx_done_old == tx_done &&
+                  (tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
                if (I40E_DEBUG_FLOW & pf->hw.debug_mask)
                        dev_info(tx_ring->dev, "HW needs some more descs to do a cacheline flush. tx_pending %d, queue %d",
                                 tx_pending, tx_ring->queue_index);
                pf->tx_sluggish_count++;
        } else {
                /* update completed stats and disarm the hang check */
-               tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
+               tx_ring->tx_stats.tx_done_old = tx_done;
                clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
        }
 
        return ret;
 }
 
-/**
- * i40e_get_head - Retrieve head from head writeback
- * @tx_ring:  tx ring to fetch head of
- *
- * Returns value of Tx ring head based on value stored
- * in head write-back location
- **/
-static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
-{
-       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
-
-       return le32_to_cpu(*(volatile __le32 *)head);
-}
-
 #define WB_STRIDE 0x3
 
 /**
@@ -2139,6 +2145,67 @@ static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
        return __i40e_maybe_stop_tx(tx_ring, size);
 }
 
+/**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @tx_flags: collected send information
+ * @hdr_len:  size of the packet header
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
+                              const u8 hdr_len)
+{
+       struct skb_frag_struct *frag;
+       bool linearize = false;
+       unsigned int size = 0;
+       u16 num_frags;
+       u16 gso_segs;
+
+       num_frags = skb_shinfo(skb)->nr_frags;
+       gso_segs = skb_shinfo(skb)->gso_segs;
+
+       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
+               u16 j = 1;
+
+               if (num_frags < (I40E_MAX_BUFFER_TXD))
+                       goto linearize_chk_done;
+               /* try the simple math, if we have too many frags per segment */
+               if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
+                   I40E_MAX_BUFFER_TXD) {
+                       linearize = true;
+                       goto linearize_chk_done;
+               }
+               frag = &skb_shinfo(skb)->frags[0];
+               size = hdr_len;
+               /* we might still have more fragments per segment */
+               do {
+                       size += skb_frag_size(frag);
+                       frag++; j++;
+                       if (j == I40E_MAX_BUFFER_TXD) {
+                               if (size < skb_shinfo(skb)->gso_size) {
+                                       linearize = true;
+                                       break;
+                               }
+                               j = 1;
+                               size -= skb_shinfo(skb)->gso_size;
+                               if (size)
+                                       j++;
+                               size += hdr_len;
+                       }
+                       num_frags--;
+               } while (num_frags);
+       } else {
+               if (num_frags >= I40E_MAX_BUFFER_TXD)
+                       linearize = true;
+       }
+
+linearize_chk_done:
+       return linearize;
+}
+
 /**
  * i40e_tx_map - Build the Tx descriptor
  * @tx_ring:  ring to send buffer on
@@ -2396,6 +2463,10 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        if (tsyn)
                tx_flags |= I40E_TX_FLAGS_TSYN;
 
+       if (i40e_chk_linearize(skb, tx_flags, hdr_len))
+               if (skb_linearize(skb))
+                       goto out_drop;
+
        skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
index 18b00231d2f117d714e7e1399aecba0061ead41a..dff0baeb1ecc092e53ef22ea373be46e79df13a2 100644 (file)
@@ -112,6 +112,7 @@ enum i40e_dyn_idx_t {
 
 #define i40e_rx_desc i40e_32byte_rx_desc
 
+#define I40E_MAX_BUFFER_TXD    8
 #define I40E_MIN_TX_LEN                17
 #define I40E_MAX_DATA_PER_TXD  8192
 
index 29004382f462ce717fd27b5b004139f5ef0efd1a..708891571dae328299e2b31e83cbf40b42726473 100644 (file)
@@ -125,6 +125,20 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
        }
 }
 
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring:  tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+       return le32_to_cpu(*(volatile __le32 *)head);
+}
+
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
  * @tx_ring: the ring of descriptors
@@ -134,10 +148,16 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
  **/
 static u32 i40e_get_tx_pending(struct i40e_ring *ring)
 {
-       u32 ntu = ((ring->next_to_clean <= ring->next_to_use)
-                       ? ring->next_to_use
-                       : ring->next_to_use + ring->count);
-       return ntu - ring->next_to_clean;
+       u32 head, tail;
+
+       head = i40e_get_head(ring);
+       tail = readl(ring->tail);
+
+       if (head != tail)
+               return (head < tail) ?
+                       tail - head : (tail + ring->count - head);
+
+       return 0;
 }
 
 /**
@@ -146,6 +166,8 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
  **/
 static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
 {
+       u32 tx_done = tx_ring->stats.packets;
+       u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
        u32 tx_pending = i40e_get_tx_pending(tx_ring);
        bool ret = false;
 
@@ -162,36 +184,20 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * run the check_tx_hang logic with a transmit completion
         * pending but without time to complete it yet.
         */
-       if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           (tx_pending >= I40E_MIN_DESC_PENDING)) {
+       if ((tx_done_old == tx_done) && tx_pending) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
-       } else if (!(tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) ||
-                  !(tx_pending < I40E_MIN_DESC_PENDING) ||
-                  !(tx_pending > 0)) {
+       } else if (tx_done_old == tx_done &&
+                  (tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
                /* update completed stats and disarm the hang check */
-               tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
+               tx_ring->tx_stats.tx_done_old = tx_done;
                clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
        }
 
        return ret;
 }
 
-/**
- * i40e_get_head - Retrieve head from head writeback
- * @tx_ring:  tx ring to fetch head of
- *
- * Returns value of Tx ring head based on value stored
- * in head write-back location
- **/
-static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
-{
-       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
-
-       return le32_to_cpu(*(volatile __le32 *)head);
-}
-
 #define WB_STRIDE 0x3
 
 /**
@@ -1206,17 +1212,16 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       if (protocol == htons(ETH_P_IP)) {
-               iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+       iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+       ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+
+       if (iph->version == 4) {
                tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
                tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
                                                 0, IPPROTO_TCP, 0);
-       } else if (skb_is_gso_v6(skb)) {
-
-               ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb)
-                                          : ipv6_hdr(skb);
+       } else if (ipv6h->version == 6) {
                tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                ipv6h->payload_len = 0;
                tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
@@ -1274,13 +1279,9 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
                                         I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
                        }
                } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
-                       if (tx_flags & I40E_TX_FLAGS_TSO) {
-                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       if (tx_flags & I40E_TX_FLAGS_TSO)
                                ip_hdr(skb)->check = 0;
-                       } else {
-                               *cd_tunneling |=
-                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-                       }
                }
 
                /* Now set the ctx descriptor fields */
@@ -1290,6 +1291,11 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
                                   ((skb_inner_network_offset(skb) -
                                        skb_transport_offset(skb)) >> 1) <<
                                   I40E_TXD_CTX_QW0_NATLEN_SHIFT;
+               if (this_ip_hdr->version == 6) {
+                       tx_flags &= ~I40E_TX_FLAGS_IPV4;
+                       tx_flags |= I40E_TX_FLAGS_IPV6;
+               }
+
 
        } else {
                network_hdr_len = skb_network_header_len(skb);
@@ -1380,6 +1386,67 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
        context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss);
 }
 
+ /**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @tx_flags: collected send information
+ * @hdr_len:  size of the packet header
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags,
+                              const u8 hdr_len)
+{
+       struct skb_frag_struct *frag;
+       bool linearize = false;
+       unsigned int size = 0;
+       u16 num_frags;
+       u16 gso_segs;
+
+       num_frags = skb_shinfo(skb)->nr_frags;
+       gso_segs = skb_shinfo(skb)->gso_segs;
+
+       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
+               u16 j = 1;
+
+               if (num_frags < (I40E_MAX_BUFFER_TXD))
+                       goto linearize_chk_done;
+               /* try the simple math, if we have too many frags per segment */
+               if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
+                   I40E_MAX_BUFFER_TXD) {
+                       linearize = true;
+                       goto linearize_chk_done;
+               }
+               frag = &skb_shinfo(skb)->frags[0];
+               size = hdr_len;
+               /* we might still have more fragments per segment */
+               do {
+                       size += skb_frag_size(frag);
+                       frag++; j++;
+                       if (j == I40E_MAX_BUFFER_TXD) {
+                               if (size < skb_shinfo(skb)->gso_size) {
+                                       linearize = true;
+                                       break;
+                               }
+                               j = 1;
+                               size -= skb_shinfo(skb)->gso_size;
+                               if (size)
+                                       j++;
+                               size += hdr_len;
+                       }
+                       num_frags--;
+               } while (num_frags);
+       } else {
+               if (num_frags >= I40E_MAX_BUFFER_TXD)
+                       linearize = true;
+       }
+
+linearize_chk_done:
+       return linearize;
+}
+
 /**
  * i40e_tx_map - Build the Tx descriptor
  * @tx_ring:  ring to send buffer on
@@ -1654,6 +1721,10 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        else if (tso)
                tx_flags |= I40E_TX_FLAGS_TSO;
 
+       if (i40e_chk_linearize(skb, tx_flags, hdr_len))
+               if (skb_linearize(skb))
+                       goto out_drop;
+
        skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
index 4e15903b2b6ded2a054981999f71e2406b1e80a2..c950a038237c2c63dc66b9bf7be887556b80a5de 100644 (file)
@@ -112,6 +112,7 @@ enum i40e_dyn_idx_t {
 
 #define i40e_rx_desc i40e_32byte_rx_desc
 
+#define I40E_MAX_BUFFER_TXD    8
 #define I40E_MIN_TX_LEN                17
 #define I40E_MAX_DATA_PER_TXD  8192
 
index 96208f17bb53be6240ae9e8d0cd30cc09041163e..2db653225a0e7713b21ecf3e80996eccf1a8a7d1 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 a681d7c0bb9f066f8d48ed068f68f0001dad8d0f..546ca4226916dbf2261525c12dc087ba35c7f4d7 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 2a210c4efb895728ec6ad12eaef9ec8f9ff7fd08..3485acf03014c7e4df64fa94a770fce00abe5a35 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 2d8ee66138e8ad48cb72daa773a67c1f421e4cac..a61009f4b2df728e05a4e54def4bb1336949f03e 100644 (file)
@@ -81,12 +81,14 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
 {
        u32 loopback_ok = 0;
        int i;
-
+       bool gro_enabled;
 
         priv->loopback_ok = 0;
        priv->validate_loopback = 1;
+       gro_enabled = priv->dev->features & NETIF_F_GRO;
 
        mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+       priv->dev->features &= ~NETIF_F_GRO;
 
        /* xmit */
        if (mlx4_en_test_loopback_xmit(priv)) {
@@ -108,6 +110,10 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
 mlx4_en_test_loopback_exit:
 
        priv->validate_loopback = 0;
+
+       if (gro_enabled)
+               priv->dev->features |= NETIF_F_GRO;
+
        mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
        return !loopback_ok;
 }
index 264bc15c1ff212ad649c3547c8a8ffc0b2c22e43..6e70ffee8e87ee2fa9957adeb5994ca346bf155b 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 2a8268e6be15d0b8682b8ad47bb4bb4ac071b243..ebbe244e80dde55068d924905e08d1d631821811 100644 (file)
@@ -453,7 +453,7 @@ struct mlx4_en_port_stats {
        unsigned long rx_chksum_none;
        unsigned long rx_chksum_complete;
        unsigned long tx_chksum_offload;
-#define NUM_PORT_STATS         9
+#define NUM_PORT_STATS         10
 };
 
 struct mlx4_en_perf_stats {
index 2bb8553bd9054b25456ec694ee25696e93ebde25..eda29dbbfcd259824f0a0fbec3876975f215d2e2 100644 (file)
@@ -412,7 +412,6 @@ err_icm:
 
 EXPORT_SYMBOL_GPL(mlx4_qp_alloc);
 
-#define MLX4_UPDATE_QP_SUPPORTED_ATTRS MLX4_UPDATE_QP_SMAC
 int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
                   enum mlx4_update_qp_attr attr,
                   struct mlx4_update_qp_params *params)
index 486e3d26cd4a9ef4bb6a23995b85ac50cd413776..6e413ac4e94011c4ea85993b8471d5adfc84d5d3 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 44e8d7d255474d30bf48577723caf9032af43854..57a6e6cd74fc3c9c99708530b431cd0e5b768f8c 100644 (file)
@@ -1239,11 +1239,9 @@ static int pasemi_mac_open(struct net_device *dev)
        if (mac->phydev)
                phy_start(mac->phydev);
 
-       init_timer(&mac->tx->clean_timer);
-       mac->tx->clean_timer.function = pasemi_mac_tx_timer;
-       mac->tx->clean_timer.data = (unsigned long)mac->tx;
-       mac->tx->clean_timer.expires = jiffies+HZ;
-       add_timer(&mac->tx->clean_timer);
+       setup_timer(&mac->tx->clean_timer, pasemi_mac_tx_timer,
+                   (unsigned long)mac->tx);
+       mod_timer(&mac->tx->clean_timer, jiffies + HZ);
 
        return 0;
 
index 6e426ae9469228ed55586bca15a8eef1dcb5e5c4..0a5e204a0179a35c15f52a3dea58729c30c2c31f 100644 (file)
@@ -354,7 +354,7 @@ struct cmd_desc_type0 {
 
 } __attribute__ ((aligned(64)));
 
-/* Note: sizeof(rcv_desc) should always be a mutliple of 2 */
+/* Note: sizeof(rcv_desc) should always be a multiple of 2 */
 struct rcv_desc {
        __le16 reference_handle;
        __le16 reserved;
@@ -499,7 +499,7 @@ struct uni_data_desc{
 #define NETXEN_IMAGE_START     0x43000 /* compressed image */
 #define NETXEN_SECONDARY_START 0x200000        /* backup images */
 #define NETXEN_PXE_START       0x3E0000        /* PXE boot rom */
-#define NETXEN_USER_START      0x3E8000        /* Firmare info */
+#define NETXEN_USER_START      0x3E8000        /* Firmware info */
 #define NETXEN_FIXED_START     0x3F0000        /* backup of crbinit */
 #define NETXEN_USER_START_OLD  NETXEN_PXE_START /* very old flash */
 
index fa4317611fd63fe81df2e23e47fa307b8c5c5348..f221126a5c4e6789cb2630a07dc58b02f0676239 100644 (file)
@@ -314,7 +314,7 @@ struct qlcnic_fdt {
 #define QLCNIC_BRDCFG_START    0x4000          /* board config */
 #define QLCNIC_BOOTLD_START    0x10000         /* bootld */
 #define QLCNIC_IMAGE_START     0x43000         /* compressed image */
-#define QLCNIC_USER_START      0x3E8000        /* Firmare info */
+#define QLCNIC_USER_START      0x3E8000        /* Firmware info */
 
 #define QLCNIC_FW_VERSION_OFFSET       (QLCNIC_USER_START+0x408)
 #define QLCNIC_FW_SIZE_OFFSET          (QLCNIC_USER_START+0x40c)
index ad0020af2193da8749534c25242047212cccc1a4..c70ab40d86989974d54c9161bf7acd8558d93c74 100644 (file)
@@ -2561,7 +2561,7 @@ static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
        int rc = -EINVAL;
 
        if (!rtl_fw_format_ok(tp, rtl_fw)) {
-               netif_err(tp, ifup, dev, "invalid firwmare\n");
+               netif_err(tp, ifup, dev, "invalid firmware\n");
                goto out;
        }
 
@@ -5067,8 +5067,6 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
        RTL_W8(ChipCmd, CmdReset);
 
        rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
-
-       netdev_reset_queue(tp->dev);
 }
 
 static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
@@ -7049,7 +7047,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
        u32 status, len;
        u32 opts[2];
        int frags;
-       bool stop_queue;
 
        if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
                netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
@@ -7090,8 +7087,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 
        txd->opts2 = cpu_to_le32(opts[1]);
 
-       netdev_sent_queue(dev, skb->len);
-
        skb_tx_timestamp(skb);
 
        /* Force memory writes to complete before releasing descriptor */
@@ -7106,16 +7101,11 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 
        tp->cur_tx += frags + 1;
 
-       stop_queue = !TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS);
+       RTL_W8(TxPoll, NPQ);
 
-       if (!skb->xmit_more || stop_queue ||
-           netif_xmit_stopped(netdev_get_tx_queue(dev, 0))) {
-               RTL_W8(TxPoll, NPQ);
-
-               mmiowb();
-       }
+       mmiowb();
 
-       if (stop_queue) {
+       if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
                /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
                 * not miss a ring update when it notices a stopped queue.
                 */
@@ -7198,7 +7188,6 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
 static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
 {
        unsigned int dirty_tx, tx_left;
-       unsigned int bytes_compl = 0, pkts_compl = 0;
 
        dirty_tx = tp->dirty_tx;
        smp_rmb();
@@ -7222,8 +7211,10 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
                rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
                                     tp->TxDescArray + entry);
                if (status & LastFrag) {
-                       pkts_compl++;
-                       bytes_compl += tx_skb->skb->len;
+                       u64_stats_update_begin(&tp->tx_stats.syncp);
+                       tp->tx_stats.packets++;
+                       tp->tx_stats.bytes += tx_skb->skb->len;
+                       u64_stats_update_end(&tp->tx_stats.syncp);
                        dev_kfree_skb_any(tx_skb->skb);
                        tx_skb->skb = NULL;
                }
@@ -7232,13 +7223,6 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
        }
 
        if (tp->dirty_tx != dirty_tx) {
-               netdev_completed_queue(tp->dev, pkts_compl, bytes_compl);
-
-               u64_stats_update_begin(&tp->tx_stats.syncp);
-               tp->tx_stats.packets += pkts_compl;
-               tp->tx_stats.bytes += bytes_compl;
-               u64_stats_update_end(&tp->tx_stats.syncp);
-
                tp->dirty_tx = dirty_tx;
                /* Sync with rtl8169_start_xmit:
                 * - publish dirty_tx ring index (write barrier)
index 4da8bd263997a17baf89b5fe7a3d2198f186827b..736d5d1624a142e902d6023cf3ee801c5169fa14 100644 (file)
@@ -508,7 +508,6 @@ static struct sh_eth_cpu_data r8a779x_data = {
        .tpauser        = 1,
        .hw_swap        = 1,
        .rmiimode       = 1,
-       .shift_rd0      = 1,
 };
 
 static void sh_eth_set_rate_sh7724(struct net_device *ndev)
@@ -1392,6 +1391,9 @@ static void sh_eth_dev_exit(struct net_device *ndev)
        msleep(2); /* max frame time at 10 Mbps < 1250 us */
        sh_eth_get_stats(ndev);
        sh_eth_reset(ndev);
+
+       /* Set MAC address again */
+       update_mac_address(ndev);
 }
 
 /* free Tx skb function */
@@ -1407,6 +1409,8 @@ static int sh_eth_txfree(struct net_device *ndev)
                txdesc = &mdp->tx_ring[entry];
                if (txdesc->status & cpu_to_edmac(mdp, TD_TACT))
                        break;
+               /* TACT bit must be checked before all the following reads */
+               rmb();
                /* Free the original skb. */
                if (mdp->tx_skbuff[entry]) {
                        dma_unmap_single(&ndev->dev, txdesc->addr,
@@ -1444,6 +1448,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        limit = boguscnt;
        rxdesc = &mdp->rx_ring[entry];
        while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) {
+               /* RACT bit must be checked before all the following reads */
+               rmb();
                desc_status = edmac_to_cpu(mdp, rxdesc->status);
                pkt_len = rxdesc->frame_length;
 
@@ -1455,8 +1461,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
 
                /* In case of almost all GETHER/ETHERs, the Receive Frame State
                 * (RFS) bits in the Receive Descriptor 0 are from bit 9 to
-                * bit 0. However, in case of the R8A7740, R8A779x, and
-                * R7S72100 the RFS bits are from bit 25 to bit 16. So, the
+                * bit 0. However, in case of the R8A7740 and R7S72100
+                * the RFS bits are from bit 25 to bit 16. So, the
                 * driver needs right shifting by 16.
                 */
                if (mdp->cd->shift_rd0)
@@ -1523,6 +1529,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                        skb_checksum_none_assert(skb);
                        rxdesc->addr = dma_addr;
                }
+               wmb(); /* RACT bit must be set after all the above writes */
                if (entry >= mdp->num_rx_ring - 1)
                        rxdesc->status |=
                                cpu_to_edmac(mdp, RD_RACT | RD_RFP | RD_RDEL);
@@ -1535,7 +1542,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        /* If we don't need to check status, don't. -KDU */
        if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) {
                /* fix the values for the next receiving if RDE is set */
-               if (intr_status & EESR_RDE) {
+               if (intr_status & EESR_RDE && mdp->reg_offset[RDFAR] != 0) {
                        u32 count = (sh_eth_read(ndev, RDFAR) -
                                     sh_eth_read(ndev, RDLAR)) >> 4;
 
@@ -2174,7 +2181,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        spin_unlock_irqrestore(&mdp->lock, flags);
 
-       if (skb_padto(skb, ETH_ZLEN))
+       if (skb_put_padto(skb, ETH_ZLEN))
                return NETDEV_TX_OK;
 
        entry = mdp->cur_tx % mdp->num_tx_ring;
@@ -2192,6 +2199,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        txdesc->buffer_length = skb->len;
 
+       wmb(); /* TACT bit must be set after all the above writes */
        if (entry >= mdp->num_tx_ring - 1)
                txdesc->status |= cpu_to_edmac(mdp, TD_TACT | TD_TDLE);
        else
index 34389b6aa67cbd26263366ca1bff769f1b27c68a..5cecec282aba8b471b60b91af594ba6374edcda7 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 6b33127ab352a43ed6a787af7eedde554241e1b3..3449893aea8d402fb2fc56582df92a04aa157c10 100644 (file)
@@ -1070,11 +1070,8 @@ static int smc_open(struct net_device *dev)
     smc->packets_waiting = 0;
 
     smc_reset(dev);
-    init_timer(&smc->media);
-    smc->media.function = media_check;
-    smc->media.data = (u_long) dev;
-    smc->media.expires = jiffies + HZ;
-    add_timer(&smc->media);
+    setup_timer(&smc->media, media_check, (u_long)dev);
+    mod_timer(&smc->media, jiffies + HZ);
 
     return 0;
 } /* smc_open */
index 88a55f95fe09bc544b0acf0e28bae507086788f8..8678e39aba08cfe0d5b3b0578348b258812ec4ec 100644 (file)
@@ -91,6 +91,11 @@ static const char version[] =
 
 #include "smc91x.h"
 
+#if defined(CONFIG_ASSABET_NEPONSET)
+#include <mach/assabet.h>
+#include <mach/neponset.h>
+#endif
+
 #ifndef SMC_NOWAIT
 # define SMC_NOWAIT            0
 #endif
@@ -2243,10 +2248,9 @@ static int smc_drv_probe(struct platform_device *pdev)
        const struct of_device_id *match = NULL;
        struct smc_local *lp;
        struct net_device *ndev;
-       struct resource *res;
+       struct resource *res, *ires;
        unsigned int __iomem *addr;
        unsigned long irq_flags = SMC_IRQ_FLAGS;
-       unsigned long irq_resflags;
        int ret;
 
        ndev = alloc_etherdev(sizeof(struct smc_local));
@@ -2338,25 +2342,23 @@ static int smc_drv_probe(struct platform_device *pdev)
                goto out_free_netdev;
        }
 
-       ndev->irq = platform_get_irq(pdev, 0);
-       if (ndev->irq <= 0) {
+       ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!ires) {
                ret = -ENODEV;
                goto out_release_io;
        }
-       /*
-        * If this platform does not specify any special irqflags, or if
-        * the resource supplies a trigger, override the irqflags with
-        * the trigger flags from the resource.
-        */
-       irq_resflags = irqd_get_trigger_type(irq_get_irq_data(ndev->irq));
-       if (irq_flags == -1 || irq_resflags & IRQF_TRIGGER_MASK)
-               irq_flags = irq_resflags & IRQF_TRIGGER_MASK;
+
+       ndev->irq = ires->start;
+
+       if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK)
+               irq_flags = ires->flags & IRQF_TRIGGER_MASK;
 
        ret = smc_request_attrib(pdev, ndev);
        if (ret)
                goto out_release_io;
-#if defined(CONFIG_SA1100_ASSABET)
-       neponset_ncr_set(NCR_ENET_OSC_EN);
+#if defined(CONFIG_ASSABET_NEPONSET)
+       if (machine_is_assabet() && machine_has_neponset())
+               neponset_ncr_set(NCR_ENET_OSC_EN);
 #endif
        platform_set_drvdata(pdev, ndev);
        ret = smc_enable_device(pdev);
index be67baf5f6778d08df4eaa06216914b77ab8f2b5..3a18501d1068c36816554f953e367ff1439c2a36 100644 (file)
  * Define your architecture specific bus configuration parameters here.
  */
 
-#if defined(CONFIG_ARCH_LUBBOCK) ||\
-    defined(CONFIG_MACH_MAINSTONE) ||\
-    defined(CONFIG_MACH_ZYLONITE) ||\
-    defined(CONFIG_MACH_LITTLETON) ||\
-    defined(CONFIG_MACH_ZYLONITE2) ||\
-    defined(CONFIG_ARCH_VIPER) ||\
-    defined(CONFIG_MACH_STARGATE2) ||\
-    defined(CONFIG_ARCH_VERSATILE)
+#if defined(CONFIG_ARM)
 
 #include <asm/mach-types.h>
 
 /* We actually can't write halfwords properly if not word aligned */
 static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 {
-       if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) {
-               unsigned int v = val << 16;
-               v |= readl(ioaddr + (reg & ~2)) & 0xffff;
-               writel(v, ioaddr + (reg & ~2));
-       } else {
-               writew(val, ioaddr + reg);
-       }
-}
-
-#elif defined(CONFIG_SA1100_PLEB)
-/* We can only do 16-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (-1)
-
-#elif defined(CONFIG_SA1100_ASSABET)
-
-#include <mach/neponset.h>
-
-/* We can only do 8-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      0
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-/* The first two address lines aren't connected... */
-#define SMC_IO_SHIFT           2
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
-#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-#elif  defined(CONFIG_MACH_LOGICPD_PXA270) ||  \
-       defined(CONFIG_MACH_NOMADIK_8815NHK)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#elif  defined(CONFIG_ARCH_INNOKOM) || \
-       defined(CONFIG_ARCH_PXA_IDP) || \
-       defined(CONFIG_ARCH_RAMSES) || \
-       defined(CONFIG_ARCH_PCM027)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-#define SMC_USE_PXA_DMA                1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-/* We actually can't write halfwords properly if not word aligned */
-static inline void
-SMC_outw(u16 val, void __iomem *ioaddr, int reg)
-{
-       if (reg & 2) {
+       if ((machine_is_mainstone() || machine_is_stargate2() ||
+            machine_is_pxa_idp()) && reg & 2) {
                unsigned int v = val << 16;
                v |= readl(ioaddr + (reg & ~2)) & 0xffff;
                writel(v, ioaddr + (reg & ~2));
@@ -237,20 +143,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define RPC_LSA_DEFAULT         RPC_LED_100_10
 #define RPC_LSB_DEFAULT         RPC_LED_TX_RX
 
-#elif defined(CONFIG_ARCH_MSM)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          IRQF_TRIGGER_HIGH
-
 #elif defined(CONFIG_COLDFIRE)
 
 #define SMC_CAN_USE_8BIT       0
index 55e89b3838f1cb60df3f2f751ba254eddbef8fa2..a0ea84fe6519badffb8b5cabf0e9892d135ea081 100644 (file)
@@ -310,11 +310,11 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
                spin_lock_irqsave(&priv->lock, flags);
                if (!priv->eee_active) {
                        priv->eee_active = 1;
-                       init_timer(&priv->eee_ctrl_timer);
-                       priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
-                       priv->eee_ctrl_timer.data = (unsigned long)priv;
-                       priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer);
-                       add_timer(&priv->eee_ctrl_timer);
+                       setup_timer(&priv->eee_ctrl_timer,
+                                   stmmac_eee_ctrl_timer,
+                                   (unsigned long)priv);
+                       mod_timer(&priv->eee_ctrl_timer,
+                                 STMMAC_LPI_T(eee_timer));
 
                        priv->hw->mac->set_eee_timer(priv->hw,
                                                     STMMAC_DEFAULT_LIT_LS,
index fb846ebba1d9b0860acf920356aedfaf9d967f27..f9b42f11950f74dd38c41a9c535a14f94c51318b 100644 (file)
@@ -272,6 +272,37 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
        struct stmmac_priv *priv = NULL;
        struct plat_stmmacenet_data *plat_dat = NULL;
        const char *mac = NULL;
+       int irq, wol_irq, lpi_irq;
+
+       /* Get IRQ information early to have an ability to ask for deferred
+        * probe if needed before we went too far with resource allocation.
+        */
+       irq = platform_get_irq_byname(pdev, "macirq");
+       if (irq < 0) {
+               if (irq != -EPROBE_DEFER) {
+                       dev_err(dev,
+                               "MAC IRQ configuration information not found\n");
+               }
+               return irq;
+       }
+
+       /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
+        * The external wake up irq can be passed through the platform code
+        * named as "eth_wake_irq"
+        *
+        * In case the wake up interrupt is not passed from the platform
+        * so the driver will continue to use the mac irq (ndev->irq)
+        */
+       wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+       if (wol_irq < 0) {
+               if (wol_irq == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               wol_irq = irq;
+       }
+
+       lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
+       if (lpi_irq == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        addr = devm_ioremap_resource(dev, res);
@@ -323,39 +354,15 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
                return PTR_ERR(priv);
        }
 
+       /* Copy IRQ values to priv structure which is now avaialble */
+       priv->dev->irq = irq;
+       priv->wol_irq = wol_irq;
+       priv->lpi_irq = lpi_irq;
+
        /* Get MAC address if available (DT) */
        if (mac)
                memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
 
-       /* Get the MAC information */
-       priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
-       if (priv->dev->irq < 0) {
-               if (priv->dev->irq != -EPROBE_DEFER) {
-                       netdev_err(priv->dev,
-                                  "MAC IRQ configuration information not found\n");
-               }
-               return priv->dev->irq;
-       }
-
-       /*
-        * On some platforms e.g. SPEAr the wake up irq differs from the mac irq
-        * The external wake up irq can be passed through the platform code
-        * named as "eth_wake_irq"
-        *
-        * In case the wake up interrupt is not passed from the platform
-        * so the driver will continue to use the mac irq (ndev->irq)
-        */
-       priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
-       if (priv->wol_irq < 0) {
-               if (priv->wol_irq == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-               priv->wol_irq = priv->dev->irq;
-       }
-
-       priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
-       if (priv->lpi_irq == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
-
        platform_set_drvdata(pdev, priv->dev);
 
        pr_debug("STMMAC platform driver registration completed");
index 4b51f903fb733cba9b9b8a3fe9539fe3bc811c84..0c5842aeb807014c632a2d713b366133d7021f56 100644 (file)
@@ -6989,10 +6989,10 @@ static int niu_class_to_ethflow(u64 class, int *flow_type)
                *flow_type = IP_USER_FLOW;
                break;
        default:
-               return 0;
+               return -EINVAL;
        }
 
-       return 1;
+       return 0;
 }
 
 static int niu_ethflow_to_class(int flow_type, u64 *class)
@@ -7198,11 +7198,9 @@ static int niu_get_ethtool_tcam_entry(struct niu *np,
        class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
                TCAM_V4KEY0_CLASS_CODE_SHIFT;
        ret = niu_class_to_ethflow(class, &fsp->flow_type);
-
        if (ret < 0) {
                netdev_info(np->dev, "niu%d: niu_class_to_ethflow failed\n",
                            parent->index);
-               ret = -EINVAL;
                goto out;
        }
 
index 7d8dd0d2182ef9f8d94d1e84b3c7a45f3364347c..a1bbaf6352ba379d209c7fc5cac33c8bfcbcb347 100644 (file)
@@ -1103,7 +1103,7 @@ static inline void cpsw_add_dual_emac_def_ale_entries(
        cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
                           port_mask, ALE_VLAN, slave->port_vlan, 0);
        cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
-               priv->host_port, ALE_VLAN, slave->port_vlan);
+               priv->host_port, ALE_VLAN | ALE_SECURE, slave->port_vlan);
 }
 
 static void soft_reset_slave(struct cpsw_slave *slave)
@@ -2466,6 +2466,7 @@ static int cpsw_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int cpsw_suspend(struct device *dev)
 {
        struct platform_device  *pdev = to_platform_device(dev);
@@ -2518,11 +2519,9 @@ static int cpsw_resume(struct device *dev)
        }
        return 0;
 }
+#endif
 
-static const struct dev_pm_ops cpsw_pm_ops = {
-       .suspend        = cpsw_suspend,
-       .resume         = cpsw_resume,
-};
+static SIMPLE_DEV_PM_OPS(cpsw_pm_ops, cpsw_suspend, cpsw_resume);
 
 static const struct of_device_id cpsw_of_mtable[] = {
        { .compatible = "ti,cpsw", },
index 98655b44b97e2d7690ef2fa28156730697098d2b..c00084d689f3ba99fe846c2e50f5b21daec73189 100644 (file)
@@ -423,6 +423,7 @@ static int davinci_mdio_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int davinci_mdio_suspend(struct device *dev)
 {
        struct davinci_mdio_data *data = dev_get_drvdata(dev);
@@ -464,10 +465,10 @@ static int davinci_mdio_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static const struct dev_pm_ops davinci_mdio_pm_ops = {
-       .suspend_late   = davinci_mdio_suspend,
-       .resume_early   = davinci_mdio_resume,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(davinci_mdio_suspend, davinci_mdio_resume)
 };
 
 #if IS_ENABLED(CONFIG_OF)
index a495931a66a1f217216cdb90a6b6989881039f32..0e0fbb5842b3d25e0d18ebaedfaeff60b006c1b7 100644 (file)
@@ -498,9 +498,9 @@ static int w5100_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (rx_count < budget) {
+               napi_complete(napi);
                w5100_write(priv, W5100_IMR, IR_S0);
                mmiowb();
-               napi_complete(napi);
        }
 
        return rx_count;
index 09322d9db5785ccb622a3ee3ec854442576bd537..4b310002258d0742031f4bcb36d395dd992d0a3d 100644 (file)
@@ -418,9 +418,9 @@ static int w5300_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (rx_count < budget) {
+               napi_complete(napi);
                w5300_write(priv, W5300_IMR, IR_S0);
                mmiowb();
-               napi_complete(napi);
        }
 
        return rx_count;
index f7e0f0f7c2e27dd19b2cbc674644cd4678074c2c..9e16a2819d4850938389c924e18f56184fedd946 100644 (file)
@@ -938,7 +938,7 @@ static void eth_set_mcast_list(struct net_device *dev)
        int i;
        static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
-       if (dev->flags & IFF_ALLMULTI) {
+       if ((dev->flags & IFF_ALLMULTI) && !(dev->flags & IFF_PROMISC)) {
                for (i = 0; i < ETH_ALEN; i++) {
                        __raw_writel(allmulti[i], &port->regs->mcast_addr[i]);
                        __raw_writel(allmulti[i], &port->regs->mcast_mask[i]);
index 924ea98bd5311b1c7197a9fe4e9b475b095069ce..54549a6223dd2f47f493ae112a06f12f3337120f 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 2a175006028b347efe1fbe6d145f311f78c80bd7..b7877a194cfe430469af8031c58efdf307eafc4f 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 4f4099d5603d0b64f2a15b66e86dbee90260cead..4fa14208d79931df1b5d8707744e93043b951424 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 e40fdfccc9c10df4ea8676a1dd59275d5d9c6b88..27ecc5c4fa2665cd42ac1ca81717255f85507113 100644 (file)
@@ -654,11 +654,14 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q,
        } /* else everything is zero */
 }
 
+/* Neighbour code has some assumptions on HH_DATA_MOD alignment */
+#define MACVTAP_RESERVE HH_DATA_OFF(ETH_HLEN)
+
 /* Get packet from user space buffer */
 static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                                struct iov_iter *from, int noblock)
 {
-       int good_linear = SKB_MAX_HEAD(NET_IP_ALIGN);
+       int good_linear = SKB_MAX_HEAD(MACVTAP_RESERVE);
        struct sk_buff *skb;
        struct macvlan_dev *vlan;
        unsigned long total_len = iov_iter_count(from);
@@ -722,7 +725,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                        linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
        }
 
-       skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen,
+       skb = macvtap_alloc_skb(&q->sk, MACVTAP_RESERVE, copylen,
                                linear, noblock, &err);
        if (!skb)
                goto err;
index 9e3af54c90102a2c113596d326d893670b7e6c24..32efbd48f32642ddabb21126384b0c21e160a403 100644 (file)
@@ -92,6 +92,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define XGBE_PHY_CDR_RATE_PROPERTY     "amd,serdes-cdr-rate"
 #define XGBE_PHY_PQ_SKEW_PROPERTY      "amd,serdes-pq-skew"
 #define XGBE_PHY_TX_AMP_PROPERTY       "amd,serdes-tx-amp"
+#define XGBE_PHY_DFE_CFG_PROPERTY      "amd,serdes-dfe-tap-config"
+#define XGBE_PHY_DFE_ENA_PROPERTY      "amd,serdes-dfe-tap-enable"
 
 #define XGBE_PHY_SPEEDS                        3
 #define XGBE_PHY_SPEED_1000            0
@@ -177,10 +179,12 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_10000_BLWC               0
 #define SPEED_10000_CDR                        0x7
 #define SPEED_10000_PLL                        0x1
-#define SPEED_10000_PQ                 0x1e
+#define SPEED_10000_PQ                 0x12
 #define SPEED_10000_RATE               0x0
 #define SPEED_10000_TXAMP              0xa
 #define SPEED_10000_WORD               0x7
+#define SPEED_10000_DFE_TAP_CONFIG     0x1
+#define SPEED_10000_DFE_TAP_ENABLE     0x7f
 
 #define SPEED_2500_BLWC                        1
 #define SPEED_2500_CDR                 0x2
@@ -189,6 +193,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_2500_RATE                        0x1
 #define SPEED_2500_TXAMP               0xf
 #define SPEED_2500_WORD                        0x1
+#define SPEED_2500_DFE_TAP_CONFIG      0x3
+#define SPEED_2500_DFE_TAP_ENABLE      0x0
 
 #define SPEED_1000_BLWC                        1
 #define SPEED_1000_CDR                 0x2
@@ -197,16 +203,25 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_1000_RATE                        0x3
 #define SPEED_1000_TXAMP               0xf
 #define SPEED_1000_WORD                        0x1
+#define SPEED_1000_DFE_TAP_CONFIG      0x3
+#define SPEED_1000_DFE_TAP_ENABLE      0x0
 
 /* SerDes RxTx register offsets */
+#define RXTX_REG6                      0x0018
 #define RXTX_REG20                     0x0050
+#define RXTX_REG22                     0x0058
 #define RXTX_REG114                    0x01c8
+#define RXTX_REG129                    0x0204
 
 /* SerDes RxTx register entry bit positions and sizes */
+#define RXTX_REG6_RESETB_RXD_INDEX     8
+#define RXTX_REG6_RESETB_RXD_WIDTH     1
 #define RXTX_REG20_BLWC_ENA_INDEX      2
 #define RXTX_REG20_BLWC_ENA_WIDTH      1
 #define RXTX_REG114_PQ_REG_INDEX       9
 #define RXTX_REG114_PQ_REG_WIDTH       7
+#define RXTX_REG129_RXDFE_CONFIG_INDEX 14
+#define RXTX_REG129_RXDFE_CONFIG_WIDTH 2
 
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
@@ -333,6 +348,18 @@ static const u32 amd_xgbe_phy_serdes_tx_amp[] = {
        SPEED_10000_TXAMP,
 };
 
+static const u32 amd_xgbe_phy_serdes_dfe_tap_cfg[] = {
+       SPEED_1000_DFE_TAP_CONFIG,
+       SPEED_2500_DFE_TAP_CONFIG,
+       SPEED_10000_DFE_TAP_CONFIG,
+};
+
+static const u32 amd_xgbe_phy_serdes_dfe_tap_ena[] = {
+       SPEED_1000_DFE_TAP_ENABLE,
+       SPEED_2500_DFE_TAP_ENABLE,
+       SPEED_10000_DFE_TAP_ENABLE,
+};
+
 enum amd_xgbe_phy_an {
        AMD_XGBE_AN_READY = 0,
        AMD_XGBE_AN_PAGE_RECEIVED,
@@ -393,6 +420,8 @@ struct amd_xgbe_phy_priv {
        u32 serdes_cdr_rate[XGBE_PHY_SPEEDS];
        u32 serdes_pq_skew[XGBE_PHY_SPEEDS];
        u32 serdes_tx_amp[XGBE_PHY_SPEEDS];
+       u32 serdes_dfe_tap_cfg[XGBE_PHY_SPEEDS];
+       u32 serdes_dfe_tap_ena[XGBE_PHY_SPEEDS];
 
        /* Auto-negotiation state machine support */
        struct mutex an_mutex;
@@ -481,11 +510,16 @@ static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev)
                status = XSIR0_IOREAD(priv, SIR0_STATUS);
                if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
                    XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
-                       return;
+                       goto rx_reset;
        }
 
        netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n",
                   status);
+
+rx_reset:
+       /* Perform Rx reset for the DFE changes */
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 0);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 1);
 }
 
 static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
@@ -534,6 +568,10 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_10000]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_10000]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_10000]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -586,6 +624,10 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_2500]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_2500]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_2500]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -638,6 +680,10 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
                           priv->serdes_blwc[XGBE_PHY_SPEED_1000]);
        XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
                           priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]);
+       XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
+                          priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_1000]);
+       XRXTX_IOWRITE(priv, RXTX_REG22,
+                     priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_1000]);
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
@@ -1668,6 +1714,38 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev)
                       sizeof(priv->serdes_tx_amp));
        }
 
+       if (device_property_present(phy_dev, XGBE_PHY_DFE_CFG_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_PHY_DFE_CFG_PROPERTY,
+                                                    priv->serdes_dfe_tap_cfg,
+                                                    XGBE_PHY_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_PHY_DFE_CFG_PROPERTY);
+                       goto err_sir1;
+               }
+       } else {
+               memcpy(priv->serdes_dfe_tap_cfg,
+                      amd_xgbe_phy_serdes_dfe_tap_cfg,
+                      sizeof(priv->serdes_dfe_tap_cfg));
+       }
+
+       if (device_property_present(phy_dev, XGBE_PHY_DFE_ENA_PROPERTY)) {
+               ret = device_property_read_u32_array(phy_dev,
+                                                    XGBE_PHY_DFE_ENA_PROPERTY,
+                                                    priv->serdes_dfe_tap_ena,
+                                                    XGBE_PHY_SPEEDS);
+               if (ret) {
+                       dev_err(dev, "invalid %s property\n",
+                               XGBE_PHY_DFE_ENA_PROPERTY);
+                       goto err_sir1;
+               }
+       } else {
+               memcpy(priv->serdes_dfe_tap_ena,
+                      amd_xgbe_phy_serdes_dfe_tap_ena,
+                      sizeof(priv->serdes_dfe_tap_ena));
+       }
+
        phydev->priv = priv;
 
        if (!priv->adev || acpi_disabled)
index cdcac6aa4260b32927d7c903e024b42e5d17861e..52cd8db2c57daad2767dec72149f4cdabbcf6917 100644 (file)
@@ -235,6 +235,25 @@ static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
        return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
 }
 
+/**
+ * phy_check_valid - check if there is a valid PHY setting which matches
+ *                  speed, duplex, and feature mask
+ * @speed: speed to match
+ * @duplex: duplex to match
+ * @features: A mask of the valid settings
+ *
+ * Description: Returns true if there is a valid setting, false otherwise.
+ */
+static inline bool phy_check_valid(int speed, int duplex, u32 features)
+{
+       unsigned int idx;
+
+       idx = phy_find_valid(phy_find_setting(speed, duplex), features);
+
+       return settings[idx].speed == speed && settings[idx].duplex == duplex &&
+               (settings[idx].setting & features);
+}
+
 /**
  * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
  * @phydev: the target phy_device struct
@@ -1045,7 +1064,6 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
                int status;
-               unsigned int idx;
 
                /* Read phy status to properly get the right settings */
                status = phy_read_status(phydev);
@@ -1077,8 +1095,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
 
                adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
                lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
-               idx = phy_find_setting(phydev->speed, phydev->duplex);
-               if (!(lp & adv & settings[idx].setting))
+               if (!phy_check_valid(phydev->speed, phydev->duplex, lp & adv))
                        goto eee_exit_err;
 
                if (clk_stop_enable) {
index 0e62274e884a89de170d668795b40c3620d41046..7d394846afc214900f9e85baa2130f6f6121ac33 100644 (file)
@@ -43,9 +43,7 @@
 
 static struct team_port *team_port_get_rcu(const struct net_device *dev)
 {
-       struct team_port *port = rcu_dereference(dev->rx_handler_data);
-
-       return team_port_exists(dev) ? port : NULL;
+       return rcu_dereference(dev->rx_handler_data);
 }
 
 static struct team_port *team_port_get_rtnl(const struct net_device *dev)
@@ -1732,11 +1730,11 @@ static int team_set_mac_address(struct net_device *dev, void *p)
        if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       rcu_read_lock();
-       list_for_each_entry_rcu(port, &team->port_list, list)
+       mutex_lock(&team->lock);
+       list_for_each_entry(port, &team->port_list, list)
                if (team->ops.port_change_dev_addr)
                        team->ops.port_change_dev_addr(team, port);
-       rcu_read_unlock();
+       mutex_unlock(&team->lock);
        return 0;
 }
 
index 3bd9678315ad651beccd96ca1b5d74bcd1e68c1e..7ba8d0885f120156c47f44884212a2fd73f604b9 100644 (file)
@@ -161,6 +161,7 @@ config USB_NET_AX8817X
            * Linksys USB200M
            * Netgear FA120
            * Sitecom LN-029
+           * Sitecom LN-028
            * Intellinet USB 2.0 Ethernet
            * ST Lab USB 2.0 Ethernet
            * TrendNet TU2-ET100
index 5c55f11572baa0a3e0dd3877ae886935cb8a6eb9..75d6f26729a30e34cdaaf8334a9cc0aaa2a01c82 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 bf49792062a2b40c2f1bd2f5a06e6eff8954ab90..1173a24feda38c3af236c84acaf8982f39c0e0b1 100644 (file)
@@ -978,6 +978,10 @@ static const struct usb_device_id  products [] = {
        // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter"
        USB_DEVICE (0x0df6, 0x0056),
        .driver_info =  (unsigned long) &ax88178_info,
+}, {
+       // Sitecom LN-028 "USB 2.0 10/100/1000 Ethernet adapter"
+       USB_DEVICE (0x0df6, 0x061c),
+       .driver_info =  (unsigned long) &ax88178_info,
 }, {
        // corega FEther USB2-TX
        USB_DEVICE (0x07aa, 0x0017),
index 9311a08565bed17cf5082a21b9c6dca7ab02dfe1..4545e78840b0d9dc80ae4392b36cfcf588f17c3a 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 80a844e0ae0383303d8fa4a6d4147fc99337f268..c3e4da9e79ca071a06082e965a3aec5bb206a77e 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 3eed708a6182e761fb79d197eadfbcbc028e5afc..1762ad3910b2e75b55db894afee887f055977b22 100644 (file)
@@ -46,8 +46,7 @@ enum cx82310_status {
 };
 
 #define CMD_PACKET_SIZE        64
-/* first command after power on can take around 8 seconds */
-#define CMD_TIMEOUT    15000
+#define CMD_TIMEOUT    100
 #define CMD_REPLY_RETRY 5
 
 #define CX82310_MTU    1514
@@ -78,8 +77,9 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
        ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf,
                           CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);
        if (ret < 0) {
-               dev_err(&dev->udev->dev, "send command %#x: error %d\n",
-                       cmd, ret);
+               if (cmd != CMD_GET_LINK_STATUS)
+                       dev_err(&dev->udev->dev, "send command %#x: error %d\n",
+                               cmd, ret);
                goto end;
        }
 
@@ -90,8 +90,10 @@ static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
                                           buf, CMD_PACKET_SIZE, &actual_len,
                                           CMD_TIMEOUT);
                        if (ret < 0) {
-                               dev_err(&dev->udev->dev,
-                                       "reply receive error %d\n", ret);
+                               if (cmd != CMD_GET_LINK_STATUS)
+                                       dev_err(&dev->udev->dev,
+                                               "reply receive error %d\n",
+                                               ret);
                                goto end;
                        }
                        if (actual_len > 0)
@@ -134,6 +136,8 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        int ret;
        char buf[15];
        struct usb_device *udev = dev->udev;
+       u8 link[3];
+       int timeout = 50;
 
        /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */
        if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0
@@ -160,6 +164,20 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        if (!dev->partial_data)
                return -ENOMEM;
 
+       /* wait for firmware to become ready (indicated by the link being up) */
+       while (--timeout) {
+               ret = cx82310_cmd(dev, CMD_GET_LINK_STATUS, true, NULL, 0,
+                                 link, sizeof(link));
+               /* the command can time out during boot - it's not an error */
+               if (!ret && link[0] == 1 && link[2] == 1)
+                       break;
+               msleep(500);
+       };
+       if (!timeout) {
+               dev_err(&udev->dev, "firmware not ready in time\n");
+               return -ETIMEDOUT;
+       }
+
        /* enable ethernet mode (?) */
        ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
        if (ret) {
@@ -300,9 +318,18 @@ static const struct driver_info    cx82310_info = {
        .tx_fixup       = cx82310_tx_fixup,
 };
 
+#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+                      USB_DEVICE_ID_MATCH_DEV_INFO, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bDeviceClass = (cl), \
+       .bDeviceSubClass = (sc), \
+       .bDeviceProtocol = (pr)
+
 static const struct usb_device_id products[] = {
        {
-               USB_DEVICE_AND_INTERFACE_INFO(0x0572, 0xcb01, 0xff, 0, 0),
+               USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0),
                .driver_info = (unsigned long) &cx82310_info
        },
        { },
index 9cdfb3fe9c156ba775d41a9d6d343ddbb5fc9b60..778e91531fac7f35480208ba35f6ae3e6c9ad5b2 100644 (file)
@@ -1594,7 +1594,7 @@ hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
                }
                cprev = cnow;
        }
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        remove_wait_queue(&tiocmget->waitq, &wait);
 
        return ret;
index 3d18bb0eee8528ece6509ec3848c3044ff5804ce..1bfe0fcaccf5ba31bf125f898ec6c624f506206e 100644 (file)
@@ -134,6 +134,11 @@ static const struct usb_device_id  products [] = {
 }, {
        USB_DEVICE(0x050d, 0x258a),     /* Belkin F5U258/F5U279 (PL-25A1) */
        .driver_info =  (unsigned long) &prolific_info,
+}, {
+       USB_DEVICE(0x3923, 0x7825),     /* National Instruments USB
+                                        * Host-to-Host Cable
+                                        */
+       .driver_info =  (unsigned long) &prolific_info,
 },
 
        { },            // END
index 438fc6bcaef15538e9c151c46fce08dc67cec1a5..9f7c0ab3b3490b947d161428406612c80dc29360 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 b94a0fbb8b3b5a74ed466c4d5a66e25f4f2e0edc..953de13267df19d6fcefe60c2008f6222ca5775c 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 449835f4331e210daad6c8717430341c1c6996ef..777757ae19732ab10ab2283645464a87a02c7b20 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 f1ff3666f090d886e6b8ecc99bc6ac09d8687ef6..59b0e9754ae39cbc38812d407688f66f5e79b539 100644 (file)
@@ -1448,8 +1448,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
 {
        int i;
 
-       for (i = 0; i < vi->max_queue_pairs; i++)
+       for (i = 0; i < vi->max_queue_pairs; i++) {
+               napi_hash_del(&vi->rq[i].napi);
                netif_napi_del(&vi->rq[i].napi);
+       }
 
        kfree(vi->rq);
        kfree(vi->sq);
@@ -1948,11 +1950,8 @@ static int virtnet_freeze(struct virtio_device *vdev)
        cancel_delayed_work_sync(&vi->refill);
 
        if (netif_running(vi->dev)) {
-               for (i = 0; i < vi->max_queue_pairs; i++) {
+               for (i = 0; i < vi->max_queue_pairs; i++)
                        napi_disable(&vi->rq[i].napi);
-                       napi_hash_del(&vi->rq[i].napi);
-                       netif_napi_del(&vi->rq[i].napi);
-               }
        }
 
        remove_vq_common(vi);
index 1e0a775ea882995d88127e4d3c2a8f3f0afb8d60..f8528a4cf54f2b0bc78b78bd705a82577530bdeb 100644 (file)
@@ -1218,7 +1218,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                        goto drop;
 
                flags &= ~VXLAN_HF_RCO;
-               vni &= VXLAN_VID_MASK;
+               vni &= VXLAN_VNI_MASK;
        }
 
        /* For backwards compatibility, only allow reserved fields to be
@@ -1239,7 +1239,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                flags &= ~VXLAN_GBP_USED_BITS;
        }
 
-       if (flags || (vni & ~VXLAN_VID_MASK)) {
+       if (flags || vni & ~VXLAN_VNI_MASK) {
                /* If there are any unprocessed flags remaining treat
                 * this as a malformed packet. This behavior diverges from
                 * VXLAN RFC (RFC7348) which stipulates that bits in reserved
index 83c39e2858bf70a1673cf2c6d9813a92f25ce4d3..88d121d43c08bedf2efc3265964188cf2b7f94a7 100644 (file)
@@ -806,21 +806,21 @@ static ssize_t cosa_read(struct file *file,
        spin_lock_irqsave(&cosa->lock, flags);
        add_wait_queue(&chan->rxwaitq, &wait);
        while (!chan->rx_status) {
-               current->state = TASK_INTERRUPTIBLE;
+               set_current_state(TASK_INTERRUPTIBLE);
                spin_unlock_irqrestore(&cosa->lock, flags);
                schedule();
                spin_lock_irqsave(&cosa->lock, flags);
                if (signal_pending(current) && chan->rx_status == 0) {
                        chan->rx_status = 1;
                        remove_wait_queue(&chan->rxwaitq, &wait);
-                       current->state = TASK_RUNNING;
+                       __set_current_state(TASK_RUNNING);
                        spin_unlock_irqrestore(&cosa->lock, flags);
                        mutex_unlock(&chan->rlock);
                        return -ERESTARTSYS;
                }
        }
        remove_wait_queue(&chan->rxwaitq, &wait);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        kbuf = chan->rxdata;
        count = chan->rxsize;
        spin_unlock_irqrestore(&cosa->lock, flags);
@@ -890,14 +890,14 @@ static ssize_t cosa_write(struct file *file,
        spin_lock_irqsave(&cosa->lock, flags);
        add_wait_queue(&chan->txwaitq, &wait);
        while (!chan->tx_status) {
-               current->state = TASK_INTERRUPTIBLE;
+               set_current_state(TASK_INTERRUPTIBLE);
                spin_unlock_irqrestore(&cosa->lock, flags);
                schedule();
                spin_lock_irqsave(&cosa->lock, flags);
                if (signal_pending(current) && chan->tx_status == 0) {
                        chan->tx_status = 1;
                        remove_wait_queue(&chan->txwaitq, &wait);
-                       current->state = TASK_RUNNING;
+                       __set_current_state(TASK_RUNNING);
                        chan->tx_status = 1;
                        spin_unlock_irqrestore(&cosa->lock, flags);
                        up(&chan->wsem);
@@ -905,7 +905,7 @@ static ssize_t cosa_write(struct file *file,
                }
        }
        remove_wait_queue(&chan->txwaitq, &wait);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        up(&chan->wsem);
        spin_unlock_irqrestore(&cosa->lock, flags);
        kfree(kbuf);
index cb366adc820b17a667a908d79db82da8519f3783..f50a6bc5d06ee0b2bb3c83c971cd5f1d81afd690 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 2b79a568e8032c1fbc33a0fb550a5da6140f2865..d23737342f4fe7b311c84a7d556cad6e94ecf1f1 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 60aa8d71e753fa936909dcc98ef915c2a2208f60..8529014e1a5e1c1b4637abc1625fd177b407f602 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 ccbdb05b28cd7e2dc457afe9443e35ac2ca3fc21..75345c1e8c3487468a23611a3072d525cdc8b8ca 100644 (file)
@@ -5370,6 +5370,7 @@ static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy,
        case 0x432a: /* BCM4321 */
        case 0x432d: /* BCM4322 */
        case 0x4352: /* BCM43222 */
+       case 0x435a: /* BCM43228 */
        case 0x4333: /* BCM4331 */
        case 0x43a2: /* BCM4360 */
        case 0x43b3: /* BCM4352 */
index defb7a44e0bc1ff554195890dcccc31bfb0c9769..7748a1ccf14fdf4a6b2864441e9b041da35558a6 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 50cdf7090198b3662b83488ff52e3868162401c5..8eff2753abadeb2704f87f88f7c5eabd75bf091b 100644 (file)
@@ -39,13 +39,22 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
        void *dcmd_buf = NULL, *wr_pointer;
        u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
 
-       brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set,
-                 cmdhdr->len);
+       if (len < sizeof(*cmdhdr)) {
+               brcmf_err("vendor command too short: %d\n", len);
+               return -EINVAL;
+       }
 
        vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
        ifp = vif->ifp;
 
-       len -= sizeof(struct brcmf_vndr_dcmd_hdr);
+       brcmf_dbg(TRACE, "ifidx=%d, cmd=%d\n", ifp->ifidx, cmdhdr->cmd);
+
+       if (cmdhdr->offset > len) {
+               brcmf_err("bad buffer offset %d > %d\n", cmdhdr->offset, len);
+               return -EINVAL;
+       }
+
+       len -= cmdhdr->offset;
        ret_len = cmdhdr->len;
        if (ret_len > 0 || len > 0) {
                if (len > BRCMF_DCMD_MAXLEN) {
index a6f22c32a27994000f578c2baff08a2f62042aa0..3811878ab9cd2057ad44785c7f3dad5cb5edcf07 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 47e64e8b9517d97dff6b96e544a731d498412ba1..cceb026e0793b45fa418e7c023855d5c0bd23a02 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 4dbef7e58c2e3dfba5be41c1f2f4cfe32c04727b..5244e43bfafbc4617720097660ec693f5d30742f 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 c3817fae16c04207136e5d45e8cc65bd3a125429..06f6cc08f451cadc7696c5b1810735288a85b1a9 100644 (file)
@@ -95,7 +95,8 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = {
        .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION,  \
        .base_params = &iwl1000_base_params,                    \
        .eeprom_params = &iwl1000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl1000_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
@@ -121,7 +122,8 @@ const struct iwl_cfg iwl1000_bg_cfg = {
        .base_params = &iwl1000_base_params,                    \
        .eeprom_params = &iwl1000_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl100_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
index 21e5d0843a62a84a0f21ff337d1b674750fa3999..890b95f497d6eca97949a5e3989926d5b4d17d38 100644 (file)
@@ -123,7 +123,9 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
        .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,          \
        .base_params = &iwl2000_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
+
 
 const struct iwl_cfg iwl2000_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
@@ -149,7 +151,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION,  \
        .base_params = &iwl2030_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl2030_2bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
@@ -170,7 +173,8 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
        .base_params = &iwl2000_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl105_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
@@ -197,7 +201,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
        .base_params = &iwl2030_base_params,                    \
        .eeprom_params = &iwl20x0_eeprom_params,                \
        .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
+       .rx_with_siso_diversity = true,                         \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl135_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
index 332bbede39e5b0fc6bb25b7ab30bbbd22c929b8b..724194e234141e707dac6eb8ec57563435957aae 100644 (file)
@@ -93,7 +93,8 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = {
        .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION,  \
        .base_params = &iwl5000_base_params,                    \
        .eeprom_params = &iwl5000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl5300_agn_cfg = {
        .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
@@ -158,7 +159,8 @@ const struct iwl_cfg iwl5350_agn_cfg = {
        .base_params = &iwl5000_base_params,                    \
        .eeprom_params = &iwl5000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl5150_agn_cfg = {
        .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
index 8f2c3c8c6b843f78f346225d371ee3ad3df54f23..21b2630763dc933db72f54fd7fadba9244d6b449 100644 (file)
@@ -145,7 +145,8 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = {
        .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6005_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
@@ -199,7 +200,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
        .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6030_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
@@ -235,7 +237,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
        .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION,  \
        .base_params = &iwl6000_g2_base_params,                 \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_RF_STATE
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6035_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
@@ -290,7 +293,8 @@ const struct iwl_cfg iwl130_bg_cfg = {
        .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION,  \
        .base_params = &iwl6000_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
-       .led_mode = IWL_LED_BLINK
+       .led_mode = IWL_LED_BLINK,                              \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6000i_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
@@ -322,7 +326,8 @@ const struct iwl_cfg iwl6000i_2bg_cfg = {
        .base_params = &iwl6050_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6050_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
@@ -347,7 +352,8 @@ const struct iwl_cfg iwl6050_2abg_cfg = {
        .base_params = &iwl6050_base_params,                    \
        .eeprom_params = &iwl6000_eeprom_params,                \
        .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
+       .internal_wimax_coex = true,                            \
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
 
 const struct iwl_cfg iwl6150_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
index 996e7f16adf9feafc50cb5d56596a2b80e0cafb3..c7154ac42c8c366d093cfb462a46d9ac98c01e02 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 1ec4d55155f7d72fecdbe19db62dd36546bb05e0..7810c41cf9a7300e0d3b9bc16bca22a44188b463 100644 (file)
@@ -793,7 +793,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
-       if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
+       if (mvmvif->phy_ctxt &&
+           IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
                               mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
index d530ef3da1071e5a421db3f4c072504b3571d8e3..542ee74f290aec1a3f356b3c69718b5029c4e708 100644 (file)
@@ -832,7 +832,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
-       if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
+       if (mvmvif->phy_ctxt &&
+           data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
        IWL_DEBUG_COEX(data->mvm,
index 1ff7ec08532d113aa5be85cb59eed8100e3f7eed..09654e73a533f7733c2a5b1e47bf6251d6267585 100644 (file)
@@ -405,7 +405,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                        &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
 
-               if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER)
+               if ((mvm->fw->ucode_capa.capa[0] &
+                    IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+                   (mvm->fw->ucode_capa.api[0] &
+                    IWL_UCODE_TLV_API_LQ_SS_PARAMS))
                        hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
                                IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
        }
@@ -2215,7 +2218,19 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
 
-       iwl_mvm_cancel_scan(mvm);
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a hw_scan when it's already stopped.  This can
+        * happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_scan_completed() and the userspace called
+        * cancel scan scan before ieee80211_scan_work() could run.
+        * To handle that, simply return if the scan is not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
+           (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+               iwl_mvm_cancel_scan(mvm);
 
        mutex_unlock(&mvm->mutex);
 }
@@ -2559,12 +2574,29 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
        int ret;
 
        mutex_lock(&mvm->mutex);
+
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a sched_scan when it's already stopped.  This
+        * can happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_sched_scan_stopped() and the userspace called
+        * stop sched scan scan before ieee80211_sched_scan_stopped_work()
+        * could run.  To handle this, simply return if the scan is
+        * not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
+           !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+               mutex_unlock(&mvm->mutex);
+               return 0;
+       }
+
        ret = iwl_mvm_scan_offload_stop(mvm, false);
        mutex_unlock(&mvm->mutex);
        iwl_mvm_wait_for_async_handlers(mvm);
 
        return ret;
-
 }
 
 static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
index 194bd1f939ca3c6a42e9c4a9d6cc7eb843c2d256..078f24cf4af3927c66e2540bc6cc6404d0c36fc7 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 7e9aa3cb325401fcf4105e278294b11657a90df1..c47c8051da7770f2a2a89c9b33868151c62f0ff6 100644 (file)
@@ -1128,8 +1128,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_NONE)
                return 0;
 
-       if (iwl_mvm_is_radio_killed(mvm))
+       if (iwl_mvm_is_radio_killed(mvm)) {
+               ret = 0;
                goto out;
+       }
 
        if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
            (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
@@ -1148,16 +1150,14 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
                IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
                               sched ? "offloaded " : "", ret);
                iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
-               return ret;
+               goto out;
        }
 
        IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
                       sched ? "offloaded " : "");
 
        ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
-       if (ret)
-               return ret;
-
+out:
        /*
         * Clear the scan status so the next scan requests will succeed. This
         * also ensures the Rx handler doesn't do anything, as the scan was
@@ -1167,7 +1167,6 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_OS)
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
 
-out:
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 
        if (notify) {
@@ -1177,7 +1176,7 @@ out:
                        ieee80211_scan_completed(mvm->hw, true);
        }
 
-       return 0;
+       return ret;
 }
 
 static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
index 54fafbf9a711fb9bacb3149fcb9f8ce1826c4b90..4b81c0bf63b0a86173afde87ef2822c0dfa8860f 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 07304e1fd64aa70b41d4c9a18762b48924a6f250..96a05406babf864fb0ff463e9b87dc4c27ba5299 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 dbd6bcf5220563c03727bccde83083032b977ff8..686dd301cd536b68d616ea0507a3e1742e12240c 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 4a4c6586a8d2dcda2b6f49a5b767bcc48304e138..8908be6dbc48233db9183247e1928bfab6eaa491 100644 (file)
@@ -946,7 +946,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
                goto nla_put_failure;
 
        genlmsg_end(skb, msg_head);
-       genlmsg_unicast(&init_net, skb, dst_portid);
+       if (genlmsg_unicast(&init_net, skb, dst_portid))
+               goto err_free_txskb;
 
        /* Enqueue the packet */
        skb_queue_tail(&data->pending, my_skb);
@@ -955,6 +956,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        return;
 
 nla_put_failure:
+       nlmsg_free(skb);
+err_free_txskb:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
        ieee80211_free_txskb(hw, my_skb);
        data->tx_failed++;
index 1d46774607116af89f96c6e835cb84775ddaa8ca..074f716020aae4e28d3e8340da846514065a94db 100644 (file)
@@ -1386,8 +1386,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
                }
 
                return true;
-       } else if (0x86DD == ether_type) {
-               return true;
+       } else if (ETH_P_IPV6 == ether_type) {
+               /* TODO: Handle any IPv6 cases that need special handling.
+                * For now, always return false
+                */
+               goto end;
        }
 
 end:
index a62170ea04818e37790eeec99fc2047e255b030f..8c45cf44ce24bac6393902ae2daf708b0ce11e6a 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 f38227afe0998a668c40e2194def6128895bb077..3aa8648080c8dee1133b9faf0b6ac0c2ad538a9b 100644 (file)
@@ -340,12 +340,11 @@ static void xenvif_get_ethtool_stats(struct net_device *dev,
        unsigned int num_queues = vif->num_queues;
        int i;
        unsigned int queue_index;
-       struct xenvif_stats *vif_stats;
 
        for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) {
                unsigned long accum = 0;
                for (queue_index = 0; queue_index < num_queues; ++queue_index) {
-                       vif_stats = &vif->queues[queue_index].stats;
+                       void *vif_stats = &vif->queues[queue_index].stats;
                        accum += *(unsigned long *)(vif_stats + xenvif_stats[i].offset);
                }
                data[i] = accum;
index f7a31d2cb3f1819fdf7ebdeb40e0f6bf44aabe0a..997cf0901ac2dc50d92f26ea2c5c4e51511b8362 100644 (file)
@@ -96,6 +96,7 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 static void make_tx_response(struct xenvif_queue *queue,
                             struct xen_netif_tx_request *txp,
                             s8       st);
+static void push_tx_responses(struct xenvif_queue *queue);
 
 static inline int tx_work_todo(struct xenvif_queue *queue);
 
@@ -657,6 +658,7 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
        do {
                spin_lock_irqsave(&queue->response_lock, flags);
                make_tx_response(queue, txp, XEN_NETIF_RSP_ERROR);
+               push_tx_responses(queue);
                spin_unlock_irqrestore(&queue->response_lock, flags);
                if (cons == end)
                        break;
@@ -1343,7 +1345,7 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s
 {
        unsigned int offset = skb_headlen(skb);
        skb_frag_t frags[MAX_SKB_FRAGS];
-       int i;
+       int i, f;
        struct ubuf_info *uarg;
        struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
 
@@ -1383,23 +1385,25 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s
                frags[i].page_offset = 0;
                skb_frag_size_set(&frags[i], len);
        }
-       /* swap out with old one */
-       memcpy(skb_shinfo(skb)->frags,
-              frags,
-              i * sizeof(skb_frag_t));
-       skb_shinfo(skb)->nr_frags = i;
-       skb->truesize += i * PAGE_SIZE;
 
-       /* remove traces of mapped pages and frag_list */
+       /* Copied all the bits from the frag list -- free it. */
        skb_frag_list_init(skb);
+       xenvif_skb_zerocopy_prepare(queue, nskb);
+       kfree_skb(nskb);
+
+       /* Release all the original (foreign) frags. */
+       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+               skb_frag_unref(skb, f);
        uarg = skb_shinfo(skb)->destructor_arg;
        /* increase inflight counter to offset decrement in callback */
        atomic_inc(&queue->inflight_packets);
        uarg->callback(uarg, true);
        skb_shinfo(skb)->destructor_arg = NULL;
 
-       xenvif_skb_zerocopy_prepare(queue, nskb);
-       kfree_skb(nskb);
+       /* Fill the skb with the new (local) frags. */
+       memcpy(skb_shinfo(skb)->frags, frags, i * sizeof(skb_frag_t));
+       skb_shinfo(skb)->nr_frags = i;
+       skb->truesize += i * PAGE_SIZE;
 
        return 0;
 }
@@ -1652,13 +1656,20 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
        unsigned long flags;
 
        pending_tx_info = &queue->pending_tx_info[pending_idx];
+
        spin_lock_irqsave(&queue->response_lock, flags);
+
        make_tx_response(queue, &pending_tx_info->req, status);
-       index = pending_index(queue->pending_prod);
+
+       /* Release the pending index before pusing the Tx response so
+        * its available before a new Tx request is pushed by the
+        * frontend.
+        */
+       index = pending_index(queue->pending_prod++);
        queue->pending_ring[index] = pending_idx;
-       /* TX shouldn't use the index before we give it back here */
-       mb();
-       queue->pending_prod++;
+
+       push_tx_responses(queue);
+
        spin_unlock_irqrestore(&queue->response_lock, flags);
 }
 
@@ -1669,7 +1680,6 @@ static void make_tx_response(struct xenvif_queue *queue,
 {
        RING_IDX i = queue->tx.rsp_prod_pvt;
        struct xen_netif_tx_response *resp;
-       int notify;
 
        resp = RING_GET_RESPONSE(&queue->tx, i);
        resp->id     = txp->id;
@@ -1679,6 +1689,12 @@ static void make_tx_response(struct xenvif_queue *queue,
                RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
 
        queue->tx.rsp_prod_pvt = ++i;
+}
+
+static void push_tx_responses(struct xenvif_queue *queue)
+{
+       int notify;
+
        RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
        if (notify)
                notify_remote_via_irq(queue->tx_irq);
index e9b960f0ff32c8af2ff404a138780ff751bf4572..720aaf6313d296bec9b9a4826f1240b0eb4c0940 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 38d1c51f58b108dbee2b2a2c83f970f60471c569..7bcaeec876c0c3a5ea80a01d13b13b186bb2227f 100644 (file)
@@ -84,8 +84,7 @@ config OF_RESOLVE
        bool
 
 config OF_OVERLAY
-       bool
-       depends on OF
+       bool "Device Tree overlays"
        select OF_DYNAMIC
        select OF_RESOLVE
 
index ad2906919d4589f4edbc0cd599a2fe7aa2938922..78a7dcbec7d8990ac37adad938a0aff3420423e2 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 0a8aeb8523fe7d54a66207f25eb145e88addb90d..8f165b112e03a285899655984491b000f0020e17 100644 (file)
@@ -714,16 +714,12 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
                                                const char *path)
 {
        struct device_node *child;
-       int len = strchrnul(path, '/') - path;
-       int term;
+       int len;
 
+       len = strcspn(path, "/:");
        if (!len)
                return NULL;
 
-       term = strchrnul(path, ':') - path;
-       if (term < len)
-               len = term;
-
        __for_each_child_of_node(parent, child) {
                const char *name = strrchr(child->full_name, '/');
                if (WARN(!name, "malformed device_node %s\n", child->full_name))
@@ -768,8 +764,12 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
 
        /* The path could begin with an alias */
        if (*path != '/') {
-               char *p = strchrnul(path, '/');
-               int len = separator ? separator - path : p - path;
+               int len;
+               const char *p = separator;
+
+               if (!p)
+                       p = strchrnul(path, '/');
+               len = p - path;
 
                /* of_aliases must not be NULL */
                if (!of_aliases)
@@ -794,6 +794,8 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
                path++; /* Increment past '/' delimiter */
                np = __of_find_node_by_path(np, path);
                path = strchrnul(path, '/');
+               if (separator && separator < path)
+                       break;
        }
        raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
index 0d7765807f4940c1aa892665a78e0b32c4128528..1a7980692f254c6917371dec5a11f77f448723cf 100644 (file)
@@ -290,7 +290,7 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
        struct device_node *p;
        const __be32 *intspec, *tmp, *addr;
        u32 intsize, intlen;
-       int i, res = -EINVAL;
+       int i, res;
 
        pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
 
@@ -323,15 +323,19 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
 
        /* Get size of interrupt specifier */
        tmp = of_get_property(p, "#interrupt-cells", NULL);
-       if (tmp == NULL)
+       if (tmp == NULL) {
+               res = -EINVAL;
                goto out;
+       }
        intsize = be32_to_cpu(*tmp);
 
        pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
 
        /* Check index */
-       if ((index + 1) * intsize > intlen)
+       if ((index + 1) * intsize > intlen) {
+               res = -EINVAL;
                goto out;
+       }
 
        /* Copy intspec into irq structure */
        intspec += index * intsize;
index 352b4f28f82cd729fb842a210e7460ff9f123833..dee9270ba5471e730518b0ddc647469c8a52776f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/idr.h>
 
 #include "of_private.h"
 
@@ -85,7 +86,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
                struct device_node *target, struct device_node *child)
 {
        const char *cname;
-       struct device_node *tchild, *grandchild;
+       struct device_node *tchild;
        int ret = 0;
 
        cname = kbasename(child->full_name);
index 0cf9a236d438a78c63e0949f9f010f4ba2f199f7..52c45c7df07ff6623c7fb7656961f8bdcf804da3 100644 (file)
@@ -92,6 +92,16 @@ static void __init of_selftest_find_node_by_name(void)
                 "option path test failed\n");
        of_node_put(np);
 
+       np = of_find_node_opts_by_path("/testcase-data:test/option", &options);
+       selftest(np && !strcmp("test/option", options),
+                "option path test, subcase #1 failed\n");
+       of_node_put(np);
+
+       np = of_find_node_opts_by_path("/testcase-data/testcase-device1:test/option", &options);
+       selftest(np && !strcmp("test/option", options),
+                "option path test, subcase #2 failed\n");
+       of_node_put(np);
+
        np = of_find_node_opts_by_path("/testcase-data:testoption", NULL);
        selftest(np, "NULL option path test failed\n");
        of_node_put(np);
@@ -102,6 +112,12 @@ static void __init of_selftest_find_node_by_name(void)
                 "option alias path test failed\n");
        of_node_put(np);
 
+       np = of_find_node_opts_by_path("testcase-alias:test/alias/option",
+                                      &options);
+       selftest(np && !strcmp("test/alias/option", options),
+                "option alias path test, subcase #1 failed\n");
+       of_node_put(np);
+
        np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL);
        selftest(np, "NULL option alias path test failed\n");
        of_node_put(np);
@@ -378,9 +394,9 @@ static void __init of_selftest_property_string(void)
        rc = of_property_match_string(np, "phandle-list-names", "first");
        selftest(rc == 0, "first expected:0 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "second");
-       selftest(rc == 1, "second expected:0 got:%i\n", rc);
+       selftest(rc == 1, "second expected:1 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "third");
-       selftest(rc == 2, "third expected:0 got:%i\n", rc);
+       selftest(rc == 2, "third expected:2 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "fourth");
        selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
        rc = of_property_match_string(np, "missing-property", "blah");
@@ -478,7 +494,6 @@ static void __init of_selftest_changeset(void)
        struct device_node *n1, *n2, *n21, *nremove, *parent, *np;
        struct of_changeset chgset;
 
-       of_changeset_init(&chgset);
        n1 = __of_node_dup(NULL, "/testcase-data/changeset/n1");
        selftest(n1, "testcase setup failure\n");
        n2 = __of_node_dup(NULL, "/testcase-data/changeset/n2");
@@ -979,7 +994,7 @@ static int of_path_platform_device_exists(const char *path)
        return pdev != NULL;
 }
 
-#if IS_ENABLED(CONFIG_I2C)
+#if IS_BUILTIN(CONFIG_I2C)
 
 /* get the i2c client device instantiated at the path */
 static struct i2c_client *of_path_to_i2c_client(const char *path)
@@ -1445,7 +1460,7 @@ static void of_selftest_overlay_11(void)
                return;
 }
 
-#if IS_ENABLED(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
+#if IS_BUILTIN(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
 
 struct selftest_i2c_bus_data {
        struct platform_device  *pdev;
@@ -1584,7 +1599,7 @@ static struct i2c_driver selftest_i2c_dev_driver = {
        .id_table = selftest_i2c_dev_id,
 };
 
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
 
 struct selftest_i2c_mux_data {
        int nchans;
@@ -1695,7 +1710,7 @@ static int of_selftest_overlay_i2c_init(void)
                        "could not register selftest i2c bus driver\n"))
                return ret;
 
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
        ret = i2c_add_driver(&selftest_i2c_mux_driver);
        if (selftest(ret == 0,
                        "could not register selftest i2c mux driver\n"))
@@ -1707,7 +1722,7 @@ static int of_selftest_overlay_i2c_init(void)
 
 static void of_selftest_overlay_i2c_cleanup(void)
 {
-#if IS_ENABLED(CONFIG_I2C_MUX)
+#if IS_BUILTIN(CONFIG_I2C_MUX)
        i2c_del_driver(&selftest_i2c_mux_driver);
 #endif
        platform_driver_unregister(&selftest_i2c_bus_driver);
@@ -1814,7 +1829,7 @@ static void __init of_selftest_overlay(void)
        of_selftest_overlay_10();
        of_selftest_overlay_11();
 
-#if IS_ENABLED(CONFIG_I2C)
+#if IS_BUILTIN(CONFIG_I2C)
        if (selftest(of_selftest_overlay_i2c_init() == 0, "i2c init failed\n"))
                goto out;
 
index 1ec694a52379ea4c753cc1b397c931bc940bb1cc..464bf492ee2ae375e8fe92e0a5446dbdf0461f9d 100644 (file)
@@ -80,7 +80,7 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
        if (err)
                return err;
 
-       resource_list_for_each_entry(win, res, list) {
+       resource_list_for_each_entry(win, res) {
                struct resource *parent, *res = win->res;
 
                switch (resource_type(res)) {
index aab55474dd0d6a4bd661ccbb160f1c2e8dc3c69c..ee082c0366ecca0d9978f9b23589646a0999a174 100644 (file)
@@ -127,7 +127,7 @@ static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
        return false;
 }
 
-static int xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
                              int offset)
 {
        struct xgene_pcie_port *port = bus->sysdata;
@@ -137,7 +137,7 @@ static int xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
                return NULL;
 
        xgene_pcie_set_rtdid_reg(bus, devfn);
-       return xgene_pcie_get_cfg_base(bus);
+       return xgene_pcie_get_cfg_base(bus) + offset;
 }
 
 static struct pci_ops xgene_pcie_ops = {
index aa012fb3834b48dbc0001565d453b2dc267009c1..312f23a8429cd9331b45afaf72a278e84bd41d83 100644 (file)
@@ -521,7 +521,8 @@ static ssize_t driver_override_store(struct device *dev,
        struct pci_dev *pdev = to_pci_dev(dev);
        char *driver_override, *old = pdev->driver_override, *cp;
 
-       if (count > PATH_MAX)
+       /* We need to keep extra room for a newline */
+       if (count >= (PAGE_SIZE - 1))
                return -EINVAL;
 
        driver_override = kstrndup(buf, count, GFP_KERNEL);
@@ -549,7 +550,7 @@ static ssize_t driver_override_show(struct device *dev,
 {
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       return sprintf(buf, "%s\n", pdev->driver_override);
+       return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
 }
 static DEVICE_ATTR_RW(driver_override);
 
index 3bb49252a098b0b3d4c72b0895044c538d2af17d..45f67c63d38539a091fde716bb0c5aa8a18b2b8b 100644 (file)
@@ -69,8 +69,7 @@ config YENTA
        tristate "CardBus yenta-compatible bridge support"
        depends on PCI
        select CARDBUS if !EXPERT
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC if PCMCIA != n
        ---help---
          This option enables support for CardBus host bridges.  Virtually
          all modern PCMCIA bridges are CardBus compatible.  A "bridge" is
@@ -110,8 +109,7 @@ config YENTA_TOSHIBA
 config PD6729
        tristate "Cirrus PD6729 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC
        help
          This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
          device, found in some older laptops and PCMCIA card readers.
@@ -119,8 +117,7 @@ config PD6729
 config I82092
        tristate "i82092 compatible bridge support"
        depends on PCMCIA && PCI
-       select PCCARD_NONSTATIC if PCMCIA != n && ISA
-       select PCCARD_PCI if PCMCIA !=n && !ISA
+       select PCCARD_NONSTATIC
        help
          This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
          found in some older laptops and more commonly in evaluation boards for the
@@ -291,9 +288,6 @@ config ELECTRA_CF
          Say Y here to support the CompactFlash controller on the
          PA Semi Electra eval board.
 
-config PCCARD_PCI
-       bool
-
 config PCCARD_NONSTATIC
        bool
 
index f1a7ca04d89e9b743fc3f82e545c52521fedef81..27e94b30cf9625b8da99d67b74308651b8077dc6 100644 (file)
@@ -12,7 +12,6 @@ obj-$(CONFIG_PCMCIA)                          += pcmcia.o
 pcmcia_rsrc-y                                  += rsrc_mgr.o
 pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC)         += rsrc_nonstatic.o
 pcmcia_rsrc-$(CONFIG_PCCARD_IODYN)             += rsrc_iodyn.o
-pcmcia_rsrc-$(CONFIG_PCCARD_PCI)               += rsrc_pci.o
 obj-$(CONFIG_PCCARD)                           += pcmcia_rsrc.o
 
 
diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c
deleted file mode 100644 (file)
index 1f67b3b..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include "cs_internal.h"
-
-
-struct pcmcia_align_data {
-       unsigned long   mask;
-       unsigned long   offset;
-};
-
-static resource_size_t pcmcia_align(void *align_data,
-                               const struct resource *res,
-                               resource_size_t size, resource_size_t align)
-{
-       struct pcmcia_align_data *data = align_data;
-       resource_size_t start;
-
-       start = (res->start & ~data->mask) + data->offset;
-       if (start < res->start)
-               start += data->mask + 1;
-       return start;
-}
-
-static struct resource *find_io_region(struct pcmcia_socket *s,
-                                       unsigned long base, int num,
-                                       unsigned long align)
-{
-       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
-                                               dev_name(&s->dev));
-       struct pcmcia_align_data data;
-       int ret;
-
-       data.mask = align - 1;
-       data.offset = base & data.mask;
-
-       ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
-                                            base, 0, pcmcia_align, &data);
-       if (ret != 0) {
-               kfree(res);
-               res = NULL;
-       }
-       return res;
-}
-
-static int res_pci_find_io(struct pcmcia_socket *s, unsigned int attr,
-                       unsigned int *base, unsigned int num,
-                       unsigned int align, struct resource **parent)
-{
-       int i, ret = 0;
-
-       /* Check for an already-allocated window that must conflict with
-        * what was asked for.  It is a hack because it does not catch all
-        * potential conflicts, just the most obvious ones.
-        */
-       for (i = 0; i < MAX_IO_WIN; i++) {
-               if (!s->io[i].res)
-                       continue;
-
-               if (!*base)
-                       continue;
-
-               if ((s->io[i].res->start & (align-1)) == *base)
-                       return -EBUSY;
-       }
-
-       for (i = 0; i < MAX_IO_WIN; i++) {
-               struct resource *res = s->io[i].res;
-               unsigned int try;
-
-               if (res && (res->flags & IORESOURCE_BITS) !=
-                       (attr & IORESOURCE_BITS))
-                       continue;
-
-               if (!res) {
-                       if (align == 0)
-                               align = 0x10000;
-
-                       res = s->io[i].res = find_io_region(s, *base, num,
-                                                               align);
-                       if (!res)
-                               return -EINVAL;
-
-                       *base = res->start;
-                       s->io[i].res->flags =
-                               ((res->flags & ~IORESOURCE_BITS) |
-                                       (attr & IORESOURCE_BITS));
-                       s->io[i].InUse = num;
-                       *parent = res;
-                       return 0;
-               }
-
-               /* Try to extend top of window */
-               try = res->end + 1;
-               if ((*base == 0) || (*base == try)) {
-                       ret = adjust_resource(s->io[i].res, res->start,
-                                             resource_size(res) + num);
-                       if (ret)
-                               continue;
-                       *base = try;
-                       s->io[i].InUse += num;
-                       *parent = res;
-                       return 0;
-               }
-
-               /* Try to extend bottom of window */
-               try = res->start - num;
-               if ((*base == 0) || (*base == try)) {
-                       ret = adjust_resource(s->io[i].res,
-                                             res->start - num,
-                                             resource_size(res) + num);
-                       if (ret)
-                               continue;
-                       *base = try;
-                       s->io[i].InUse += num;
-                       *parent = res;
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static struct resource *res_pci_find_mem(u_long base, u_long num,
-               u_long align, int low, struct pcmcia_socket *s)
-{
-       struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
-                                               dev_name(&s->dev));
-       struct pcmcia_align_data data;
-       unsigned long min;
-       int ret;
-
-       if (align < 0x20000)
-               align = 0x20000;
-       data.mask = align - 1;
-       data.offset = base & data.mask;
-
-       min = 0;
-       if (!low)
-               min = 0x100000UL;
-
-       ret = pci_bus_alloc_resource(s->cb_dev->bus,
-                       res, num, 1, min, 0,
-                       pcmcia_align, &data);
-
-       if (ret != 0) {
-               kfree(res);
-               res = NULL;
-       }
-       return res;
-}
-
-
-static int res_pci_init(struct pcmcia_socket *s)
-{
-       if (!s->cb_dev || !(s->features & SS_CAP_PAGE_REGS)) {
-               dev_err(&s->dev, "not supported by res_pci\n");
-               return -EOPNOTSUPP;
-       }
-       return 0;
-}
-
-struct pccard_resource_ops pccard_nonstatic_ops = {
-       .validate_mem = NULL,
-       .find_io = res_pci_find_io,
-       .find_mem = res_pci_find_mem,
-       .init = res_pci_init,
-       .exit = NULL,
-};
-EXPORT_SYMBOL(pccard_nonstatic_ops);
index 7c99ca256f059f79d4b288140da3feef5e0a67f8..8ccc3952c13dca6287b04a6b62fe50d1ceb076d6 100644 (file)
@@ -37,7 +37,7 @@ static int armada375_usb_phy_init(struct phy *phy)
        struct armada375_cluster_phy *cluster_phy;
        u32 reg;
 
-       cluster_phy = dev_get_drvdata(phy->dev.parent);
+       cluster_phy = phy_get_drvdata(phy);
        if (!cluster_phy)
                return -ENODEV;
 
@@ -131,6 +131,7 @@ static int armada375_usb_phy_probe(struct platform_device *pdev)
        cluster_phy->reg = usb_cluster_base;
 
        dev_set_drvdata(dev, cluster_phy);
+       phy_set_drvdata(phy, cluster_phy);
 
        phy_provider = devm_of_phy_provider_register(&pdev->dev,
                                                     armada375_usb_phy_xlate);
index a12d35338313bd4f4a67117f3c5c3f76030e53fd..3791838f4bd4b14e145dd5718a3030c4b89d9f3b 100644 (file)
@@ -52,7 +52,9 @@ static void devm_phy_consume(struct device *dev, void *res)
 
 static int devm_phy_match(struct device *dev, void *res, void *match_data)
 {
-       return res == match_data;
+       struct phy **phy = res;
+
+       return *phy == match_data;
 }
 
 /**
@@ -223,6 +225,7 @@ int phy_init(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->init_count == 0 && phy->ops->init) {
@@ -231,8 +234,6 @@ int phy_init(struct phy *phy)
                        dev_err(&phy->dev, "phy init failed --> %d\n", ret);
                        goto out;
                }
-       } else {
-               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->init_count;
 
@@ -253,6 +254,7 @@ int phy_exit(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->init_count == 1 && phy->ops->exit) {
@@ -287,6 +289,7 @@ int phy_power_on(struct phy *phy)
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
+       ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
        if (phy->power_count == 0 && phy->ops->power_on) {
@@ -295,8 +298,6 @@ int phy_power_on(struct phy *phy)
                        dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
                        goto out;
                }
-       } else {
-               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->power_count;
        mutex_unlock(&phy->mutex);
index f86cbe68ddaf30fd1a5a377c2f7d9dfb1c259c8f..179cbf9451aacf1aca440e46eb05493f41037e48 100644 (file)
@@ -30,28 +30,13 @@ struct exynos_dp_video_phy {
        const struct exynos_dp_video_phy_drvdata *drvdata;
 };
 
-static void exynos_dp_video_phy_pwr_isol(struct exynos_dp_video_phy *state,
-                                                       unsigned int on)
-{
-       unsigned int val;
-
-       if (IS_ERR(state->regs))
-               return;
-
-       val = on ? 0 : EXYNOS5_PHY_ENABLE;
-
-       regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
-                          EXYNOS5_PHY_ENABLE, val);
-}
-
 static int exynos_dp_video_phy_power_on(struct phy *phy)
 {
        struct exynos_dp_video_phy *state = phy_get_drvdata(phy);
 
        /* Disable power isolation on DP-PHY */
-       exynos_dp_video_phy_pwr_isol(state, 0);
-
-       return 0;
+       return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
+                                 EXYNOS5_PHY_ENABLE, EXYNOS5_PHY_ENABLE);
 }
 
 static int exynos_dp_video_phy_power_off(struct phy *phy)
@@ -59,9 +44,8 @@ static int exynos_dp_video_phy_power_off(struct phy *phy)
        struct exynos_dp_video_phy *state = phy_get_drvdata(phy);
 
        /* Enable power isolation on DP-PHY */
-       exynos_dp_video_phy_pwr_isol(state, 1);
-
-       return 0;
+       return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
+                                 EXYNOS5_PHY_ENABLE, 0);
 }
 
 static struct phy_ops exynos_dp_video_phy_ops = {
index f017b2f2a54ecb18c8aa7b0fed3c375f790e48d4..df7519a39ba0b15fd9181a3c3c9bcba17fcd34e9 100644 (file)
@@ -43,7 +43,6 @@ struct exynos_mipi_video_phy {
        } phys[EXYNOS_MIPI_PHYS_NUM];
        spinlock_t slock;
        void __iomem *regs;
-       struct mutex mutex;
        struct regmap *regmap;
 };
 
@@ -59,8 +58,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
        else
                reset = EXYNOS4_MIPI_PHY_SRESETN;
 
-       if (state->regmap) {
-               mutex_lock(&state->mutex);
+       spin_lock(&state->slock);
+
+       if (!IS_ERR(state->regmap)) {
                regmap_read(state->regmap, offset, &val);
                if (on)
                        val |= reset;
@@ -72,11 +72,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
                else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
                        val &= ~EXYNOS4_MIPI_PHY_ENABLE;
                regmap_write(state->regmap, offset, val);
-               mutex_unlock(&state->mutex);
        } else {
                addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
 
-               spin_lock(&state->slock);
                val = readl(addr);
                if (on)
                        val |= reset;
@@ -90,9 +88,9 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state,
                        val &= ~EXYNOS4_MIPI_PHY_ENABLE;
 
                writel(val, addr);
-               spin_unlock(&state->slock);
        }
 
+       spin_unlock(&state->slock);
        return 0;
 }
 
@@ -158,7 +156,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
 
        dev_set_drvdata(dev, state);
        spin_lock_init(&state->slock);
-       mutex_init(&state->mutex);
 
        for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
                struct phy *phy = devm_phy_create(dev, NULL,
index 236a52ad94eb705a6be6ea9813838ded256f76e1..f30bbb0fb3b2652e897c1922a7f51e48b3dc270f 100644 (file)
@@ -250,7 +250,6 @@ static const struct samsung_usb2_common_phy exynos4210_phys[] = {
                .power_on       = exynos4210_power_on,
                .power_off      = exynos4210_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
index 0b9de88579b13264a0eae49c4e159bad70aac3b1..765da90a536f057f9e3ccfc4bfe24868a388a63f 100644 (file)
@@ -361,7 +361,6 @@ static const struct samsung_usb2_common_phy exynos4x12_phys[] = {
                .power_on       = exynos4x12_power_on,
                .power_off      = exynos4x12_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos3250_usb2_phy_config = {
index 04374018425f9ab488dea49dd797f68aa5b339c1..e2a0be750ad962d82e2666e5005a8b8daf97f381 100644 (file)
@@ -531,7 +531,7 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
 {
        struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
 
-       if (WARN_ON(args->args[0] > EXYNOS5_DRDPHYS_NUM))
+       if (WARN_ON(args->args[0] >= EXYNOS5_DRDPHYS_NUM))
                return ERR_PTR(-ENODEV);
 
        return phy_drd->phys[args->args[0]].phy;
index 1c139aa0d074324e74a5f95bb06e83cea2818abf..2ed1735a076a1f8a50898de3d3de28bc7dfa235d 100644 (file)
@@ -391,7 +391,6 @@ static const struct samsung_usb2_common_phy exynos5250_phys[] = {
                .power_on       = exynos5250_power_on,
                .power_off      = exynos5250_power_off,
        },
-       {},
 };
 
 const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
index 34915b4202f18c5249a059dd42aa914fee2e7f2d..d6b22659cac11cfb4187cf9347ac86774f79de5e 100644 (file)
@@ -147,6 +147,9 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
        priv->base = devm_ioremap(dev, res->start, resource_size(res));
        if (!priv->base)
                return -ENOMEM;
index 9b2848e6115d44d050d7858ac75d01df60f71da3..933435214acce1db8895b95cc739138288b3de4b 100644 (file)
@@ -228,6 +228,7 @@ struct miphy28lp_dev {
        struct regmap *regmap;
        struct mutex miphy_mutex;
        struct miphy28lp_phy **phys;
+       int nphys;
 };
 
 struct miphy_initval {
@@ -1116,7 +1117,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       for (index = 0; index < of_get_child_count(dev->of_node); index++)
+       for (index = 0; index < miphy_dev->nphys; index++)
                if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
                        miphy_phy = miphy_dev->phys[index];
                        break;
@@ -1138,6 +1139,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
 
 static struct phy_ops miphy28lp_ops = {
        .init = miphy28lp_init,
+       .owner = THIS_MODULE,
 };
 
 static int miphy28lp_probe_resets(struct device_node *node,
@@ -1200,16 +1202,15 @@ static int miphy28lp_probe(struct platform_device *pdev)
        struct miphy28lp_dev *miphy_dev;
        struct phy_provider *provider;
        struct phy *phy;
-       int chancount, port = 0;
-       int ret;
+       int ret, port = 0;
 
        miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
        if (!miphy_dev)
                return -ENOMEM;
 
-       chancount = of_get_child_count(np);
-       miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
-                                      GFP_KERNEL);
+       miphy_dev->nphys = of_get_child_count(np);
+       miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
+                                      sizeof(*miphy_dev->phys), GFP_KERNEL);
        if (!miphy_dev->phys)
                return -ENOMEM;
 
index 6c80154e8bffb23253e03d546edd68a11ad3e0b0..51b459db9137417bb26fa971df92e6d8e86121ed 100644 (file)
@@ -150,6 +150,7 @@ struct miphy365x_dev {
        struct regmap *regmap;
        struct mutex miphy_mutex;
        struct miphy365x_phy **phys;
+       int nphys;
 };
 
 /*
@@ -485,7 +486,7 @@ static struct phy *miphy365x_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       for (index = 0; index < of_get_child_count(dev->of_node); index++)
+       for (index = 0; index < miphy_dev->nphys; index++)
                if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
                        miphy_phy = miphy_dev->phys[index];
                        break;
@@ -541,16 +542,15 @@ static int miphy365x_probe(struct platform_device *pdev)
        struct miphy365x_dev *miphy_dev;
        struct phy_provider *provider;
        struct phy *phy;
-       int chancount, port = 0;
-       int ret;
+       int ret, port = 0;
 
        miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
        if (!miphy_dev)
                return -ENOMEM;
 
-       chancount = of_get_child_count(np);
-       miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
-                                      GFP_KERNEL);
+       miphy_dev->nphys = of_get_child_count(np);
+       miphy_dev->phys = devm_kcalloc(&pdev->dev, miphy_dev->nphys,
+                                      sizeof(*miphy_dev->phys), GFP_KERNEL);
        if (!miphy_dev->phys)
                return -ENOMEM;
 
index efe724f97e02fbf9eba84c215628993fa3ea1274..93252e053a31ca752fe54bd0fc71760d318f2579 100644 (file)
@@ -360,7 +360,7 @@ static void __exit omap_control_phy_exit(void)
 }
 module_exit(omap_control_phy_exit);
 
-MODULE_ALIAS("platform: omap_control_phy");
+MODULE_ALIAS("platform:omap_control_phy");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP Control Module PHY Driver");
 MODULE_LICENSE("GPL v2");
index 6f4aef3db2481de0dc03df70521242a9be5d7fa5..4757e765696a232d1926ece274ef35111188cdc1 100644 (file)
@@ -296,10 +296,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
                        dev_warn(&pdev->dev,
                                 "found usb_otg_ss_refclk960m, please fix DTS\n");
                }
-       } else {
-               clk_prepare(phy->optclk);
        }
 
+       if (!IS_ERR(phy->optclk))
+               clk_prepare(phy->optclk);
+
        usb_add_phy_dev(&phy->phy);
 
        return 0;
@@ -383,7 +384,7 @@ static struct platform_driver omap_usb2_driver = {
 
 module_platform_driver(omap_usb2_driver);
 
-MODULE_ALIAS("platform: omap_usb2");
+MODULE_ALIAS("platform:omap_usb2");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("OMAP USB2 phy driver");
 MODULE_LICENSE("GPL v2");
index 22011c3b6a4bbdc3a3734a3ca27c665fcf099de8..7d4c33643768808780f71455900bc7dd51329103 100644 (file)
@@ -61,8 +61,6 @@ static int rockchip_usb_phy_power_off(struct phy *_phy)
                return ret;
 
        clk_disable_unprepare(phy->clk);
-       if (ret)
-               return ret;
 
        return 0;
 }
@@ -78,8 +76,10 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
 
        /* Power up usb phy analog blocks by set siddq 0 */
        ret = rockchip_usb_phy_power(phy, 0);
-       if (ret)
+       if (ret) {
+               clk_disable_unprepare(phy->clk);
                return ret;
+       }
 
        return 0;
 }
index 95c88f929f27f7d4113961e90215f3e769fe75f5..2ba610b72ca202842df7f6b43b18c7da17af1d1c 100644 (file)
@@ -165,15 +165,11 @@ static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy)
                cpu_relax();
                val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
                if (val & PLL_LOCK)
-                       break;
+                       return 0;
        } while (!time_after(jiffies, timeout));
 
-       if (!(val & PLL_LOCK)) {
-               dev_err(phy->dev, "DPLL failed to lock\n");
-               return -EBUSY;
-       }
-
-       return 0;
+       dev_err(phy->dev, "DPLL failed to lock\n");
+       return -EBUSY;
 }
 
 static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
@@ -608,7 +604,7 @@ static struct platform_driver ti_pipe3_driver = {
 
 module_platform_driver(ti_pipe3_driver);
 
-MODULE_ALIAS("platform: ti_pipe3");
+MODULE_ALIAS("platform:ti_pipe3");
 MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TI PIPE3 phy driver");
 MODULE_LICENSE("GPL v2");
index 8e87f54671f32de11915a7921824fc4a8929ab84..bc42d6a8939f4efd85fb1e10ea6d12faa1b76e97 100644 (file)
@@ -666,7 +666,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        twl->dev                = &pdev->dev;
        twl->irq                = platform_get_irq(pdev, 0);
        twl->vbus_supplied      = false;
-       twl->linkstat           = -EINVAL;
        twl->linkstat           = OMAP_MUSB_UNKNOWN;
 
        twl->phy.dev            = twl->dev;
index 29214a36ea28ef0c13ab972693f23e004fa77612..2263cd01003211e6d81a39fcb7a48538ba08e2c1 100644 (file)
@@ -1704,7 +1704,6 @@ static int xgene_phy_probe(struct platform_device *pdev)
        for (i = 0; i < MAX_LANE; i++)
                ctx->sata_param.speed[i] = 2; /* Default to Gen3 */
 
-       ctx->dev = &pdev->dev;
        platform_set_drvdata(pdev, ctx);
 
        ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops);
index 5afe03e28b911223c8909229d513a7c0e99fef4e..2062c224e32fbe7ee73da7b283205040fbd7164c 100644 (file)
 #define BYT_DIR_MASK           (BIT(1) | BIT(2))
 #define BYT_TRIG_MASK          (BIT(26) | BIT(25) | BIT(24))
 
+#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | \
+                                BYT_PIN_MUX)
+#define BYT_VAL_RESTORE_MASK   (BYT_DIR_MASK | BYT_LEVEL)
+
 #define BYT_NGPIO_SCORE                102
 #define BYT_NGPIO_NCORE                28
 #define BYT_NGPIO_SUS          44
@@ -134,12 +138,18 @@ static struct pinctrl_gpio_range byt_ranges[] = {
        },
 };
 
+struct byt_gpio_pin_context {
+       u32 conf0;
+       u32 val;
+};
+
 struct byt_gpio {
        struct gpio_chip                chip;
        struct platform_device          *pdev;
        spinlock_t                      lock;
        void __iomem                    *reg_base;
        struct pinctrl_gpio_range       *range;
+       struct byt_gpio_pin_context     *saved_context;
 };
 
 #define to_byt_gpio(c) container_of(c, struct byt_gpio, chip)
@@ -158,40 +168,62 @@ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
        return vg->reg_base + reg_offset + reg;
 }
 
-static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned offset)
+{
+       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       unsigned long flags;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+       value = readl(reg);
+       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
+       writel(value, reg);
+       spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset)
 {
        /* SCORE pin 92-93 */
        if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
                offset >= 92 && offset <= 93)
-               return true;
+               return 1;
 
        /* SUS pin 11-21 */
        if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
                offset >= 11 && offset <= 21)
-               return true;
+               return 1;
 
-       return false;
+       return 0;
 }
 
 static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
        void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
-       u32 value;
-       bool special;
+       u32 value, gpio_mux;
 
        /*
         * In most cases, func pin mux 000 means GPIO function.
         * But, some pins may have func pin mux 001 represents
-        * GPIO function. Only allow user to export pin with
-        * func pin mux preset as GPIO function by BIOS/FW.
+        * GPIO function.
+        *
+        * Because there are devices out there where some pins were not
+        * configured correctly we allow changing the mux value from
+        * request (but print out warning about that).
         */
        value = readl(reg) & BYT_PIN_MUX;
-       special = is_special_pin(vg, offset);
-       if ((special && value != 1) || (!special && value)) {
-               dev_err(&vg->pdev->dev,
-                       "pin %u cannot be used as GPIO.\n", offset);
-               return -EINVAL;
+       gpio_mux = byt_get_gpio_mux(vg, offset);
+       if (WARN_ON(gpio_mux != value)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&vg->lock, flags);
+               value = readl(reg) & ~BYT_PIN_MUX;
+               value |= gpio_mux;
+               writel(value, reg);
+               spin_unlock_irqrestore(&vg->lock, flags);
+
+               dev_warn(&vg->pdev->dev,
+                        "pin %u forcibly re-configured as GPIO\n", offset);
        }
 
        pm_runtime_get(&vg->pdev->dev);
@@ -202,14 +234,8 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
-       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
-       u32 value;
-
-       /* clear interrupt triggering */
-       value = readl(reg);
-       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
-       writel(value, reg);
 
+       byt_gpio_clear_triggering(vg, offset);
        pm_runtime_put(&vg->pdev->dev);
 }
 
@@ -236,23 +262,13 @@ static int byt_irq_type(struct irq_data *d, unsigned type)
        value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG |
                   BYT_TRIG_LVL);
 
-       switch (type) {
-       case IRQ_TYPE_LEVEL_HIGH:
-               value |= BYT_TRIG_LVL;
-       case IRQ_TYPE_EDGE_RISING:
-               value |= BYT_TRIG_POS;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               value |= BYT_TRIG_LVL;
-       case IRQ_TYPE_EDGE_FALLING:
-               value |= BYT_TRIG_NEG;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
-               break;
-       }
        writel(value, reg);
 
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+       else if (type & IRQ_TYPE_LEVEL_MASK)
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+
        spin_unlock_irqrestore(&vg->lock, flags);
 
        return 0;
@@ -410,58 +426,80 @@ static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
        struct irq_data *data = irq_desc_get_irq_data(desc);
        struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
        struct irq_chip *chip = irq_data_get_irq_chip(data);
-       u32 base, pin, mask;
+       u32 base, pin;
        void __iomem *reg;
-       u32 pending;
+       unsigned long pending;
        unsigned virq;
-       int looplimit = 0;
 
        /* check from GPIO controller which pin triggered the interrupt */
        for (base = 0; base < vg->chip.ngpio; base += 32) {
-
                reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
-
-               while ((pending = readl(reg))) {
-                       pin = __ffs(pending);
-                       mask = BIT(pin);
-                       /* Clear before handling so we can't lose an edge */
-                       writel(mask, reg);
-
+               pending = readl(reg);
+               for_each_set_bit(pin, &pending, 32) {
                        virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
                        generic_handle_irq(virq);
-
-                       /* In case bios or user sets triggering incorretly a pin
-                        * might remain in "interrupt triggered" state.
-                        */
-                       if (looplimit++ > 32) {
-                               dev_err(&vg->pdev->dev,
-                                       "Gpio %d interrupt flood, disabling\n",
-                                       base + pin);
-
-                               reg = byt_gpio_reg(&vg->chip, base + pin,
-                                                  BYT_CONF0_REG);
-                               mask = readl(reg);
-                               mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
-                                         BYT_TRIG_LVL);
-                               writel(mask, reg);
-                               mask = readl(reg); /* flush */
-                               break;
-                       }
                }
        }
        chip->irq_eoi(data);
 }
 
+static void byt_irq_ack(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+       unsigned offset = irqd_to_hwirq(d);
+       void __iomem *reg;
+
+       reg = byt_gpio_reg(&vg->chip, offset, BYT_INT_STAT_REG);
+       writel(BIT(offset % 32), reg);
+}
+
 static void byt_irq_unmask(struct irq_data *d)
 {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+       unsigned offset = irqd_to_hwirq(d);
+       unsigned long flags;
+       void __iomem *reg;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+
+       reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       value = readl(reg);
+
+       switch (irqd_get_trigger_type(d)) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_RISING:
+               value |= BYT_TRIG_POS;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_FALLING:
+               value |= BYT_TRIG_NEG;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
+               break;
+       }
+
+       writel(value, reg);
+
+       spin_unlock_irqrestore(&vg->lock, flags);
 }
 
 static void byt_irq_mask(struct irq_data *d)
 {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct byt_gpio *vg = to_byt_gpio(gc);
+
+       byt_gpio_clear_triggering(vg, irqd_to_hwirq(d));
 }
 
 static struct irq_chip byt_irqchip = {
        .name = "BYT-GPIO",
+       .irq_ack = byt_irq_ack,
        .irq_mask = byt_irq_mask,
        .irq_unmask = byt_irq_unmask,
        .irq_set_type = byt_irq_type,
@@ -472,6 +510,21 @@ static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
 {
        void __iomem *reg;
        u32 base, value;
+       int i;
+
+       /*
+        * Clear interrupt triggers for all pins that are GPIOs and
+        * do not use direct IRQ mode. This will prevent spurious
+        * interrupts from misconfigured pins.
+        */
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               value = readl(byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG));
+               if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i) &&
+                   !(value & BYT_DIRECT_IRQ_EN)) {
+                       byt_gpio_clear_triggering(vg, i);
+                       dev_dbg(&vg->pdev->dev, "disabling GPIO %d\n", i);
+               }
+       }
 
        /* clear interrupt status trigger registers */
        for (base = 0; base < vg->chip.ngpio; base += 32) {
@@ -541,6 +594,11 @@ static int byt_gpio_probe(struct platform_device *pdev)
        gc->can_sleep = false;
        gc->dev = dev;
 
+#ifdef CONFIG_PM_SLEEP
+       vg->saved_context = devm_kcalloc(&pdev->dev, gc->ngpio,
+                                      sizeof(*vg->saved_context), GFP_KERNEL);
+#endif
+
        ret = gpiochip_add(gc);
        if (ret) {
                dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
@@ -569,6 +627,69 @@ static int byt_gpio_probe(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int byt_gpio_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               void __iomem *reg;
+               u32 value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG);
+               value = readl(reg) & BYT_CONF0_RESTORE_MASK;
+               vg->saved_context[i].conf0 = value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG);
+               value = readl(reg) & BYT_VAL_RESTORE_MASK;
+               vg->saved_context[i].val = value;
+       }
+
+       return 0;
+}
+
+static int byt_gpio_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               void __iomem *reg;
+               u32 value;
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG);
+               value = readl(reg);
+               if ((value & BYT_CONF0_RESTORE_MASK) !=
+                    vg->saved_context[i].conf0) {
+                       value &= ~BYT_CONF0_RESTORE_MASK;
+                       value |= vg->saved_context[i].conf0;
+                       writel(value, reg);
+                       dev_info(dev, "restored pin %d conf0 %#08x", i, value);
+               }
+
+               reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG);
+               value = readl(reg);
+               if ((value & BYT_VAL_RESTORE_MASK) !=
+                    vg->saved_context[i].val) {
+                       u32 v;
+
+                       v = value & ~BYT_VAL_RESTORE_MASK;
+                       v |= vg->saved_context[i].val;
+                       if (v != value) {
+                               writel(v, reg);
+                               dev_dbg(dev, "restored pin %d val %#08x\n",
+                                       i, v);
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
 static int byt_gpio_runtime_suspend(struct device *dev)
 {
        return 0;
@@ -580,8 +701,9 @@ static int byt_gpio_runtime_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops byt_gpio_pm_ops = {
-       .runtime_suspend = byt_gpio_runtime_suspend,
-       .runtime_resume = byt_gpio_runtime_resume,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(byt_gpio_suspend, byt_gpio_resume)
+       SET_RUNTIME_PM_OPS(byt_gpio_runtime_suspend, byt_gpio_runtime_resume,
+                          NULL)
 };
 
 static const struct acpi_device_id byt_gpio_acpi_match[] = {
index 3034fd03bced3ff7587f8bfd248c7bb212a0c16c..82f691eeeec4d82cd5e75b7a96be719befbcd57f 100644 (file)
@@ -1226,6 +1226,7 @@ static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
                                     int value)
 {
+       chv_gpio_set(chip, offset, value);
        return pinctrl_gpio_direction_output(chip->base + offset);
 }
 
index f4cd0b9b2438b3548fafa4746b6c6a6cf8874bb4..a4814066ea0876d7f52063f5ba2cfb5ca5a6f6d3 100644 (file)
@@ -1477,28 +1477,25 @@ static void gpio_irq_ack(struct irq_data *d)
        /* the interrupt is already cleared before by reading ISR */
 }
 
-static unsigned int gpio_irq_startup(struct irq_data *d)
+static int gpio_irq_request_res(struct irq_data *d)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
        unsigned        pin = d->hwirq;
        int ret;
 
        ret = gpiochip_lock_as_irq(&at91_gpio->chip, pin);
-       if (ret) {
+       if (ret)
                dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n",
                        d->hwirq);
-               return ret;
-       }
-       gpio_irq_unmask(d);
-       return 0;
+
+       return ret;
 }
 
-static void gpio_irq_shutdown(struct irq_data *d)
+static void gpio_irq_release_res(struct irq_data *d)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
        unsigned        pin = d->hwirq;
 
-       gpio_irq_mask(d);
        gpiochip_unlock_as_irq(&at91_gpio->chip, pin);
 }
 
@@ -1577,8 +1574,8 @@ void at91_pinctrl_gpio_resume(void)
 static struct irq_chip gpio_irqchip = {
        .name           = "GPIO",
        .irq_ack        = gpio_irq_ack,
-       .irq_startup    = gpio_irq_startup,
-       .irq_shutdown   = gpio_irq_shutdown,
+       .irq_request_resources = gpio_irq_request_res,
+       .irq_release_resources = gpio_irq_release_res,
        .irq_disable    = gpio_irq_mask,
        .irq_mask       = gpio_irq_mask,
        .irq_unmask     = gpio_irq_unmask,
index 24c5d88f943f7809910507727ff50d4a43532530..3c68a8e5e0dd4d4bbb8d6fae4166a6bf92e521a2 100644 (file)
@@ -1011,6 +1011,7 @@ static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
        .pins = sun4i_a10_pins,
        .npins = ARRAY_SIZE(sun4i_a10_pins),
        .irq_banks = 1,
+       .irq_read_needs_mux = true,
 };
 
 static int sun4i_a10_pinctrl_probe(struct platform_device *pdev)
index 3d07443377362f0b84f59d971dcf73ecdf1d236c..f8e171b7669380d3d1f018124e04488fd4682f8f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 
 #include "../core.h"
+#include "../../gpio/gpiolib.h"
 #include "pinctrl-sunxi.h"
 
 static struct irq_chip sunxi_pinctrl_edge_irq_chip;
@@ -464,10 +465,19 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
 static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
-
        u32 reg = sunxi_data_reg(offset);
        u8 index = sunxi_data_offset(offset);
-       u32 val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+       u32 set_mux = pctl->desc->irq_read_needs_mux &&
+                       test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
+       u32 val;
+
+       if (set_mux)
+               sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_INPUT);
+
+       val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+
+       if (set_mux)
+               sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_IRQ);
 
        return val;
 }
index 5a51523a34599daba95571cb0d8b2597fdf4f45c..e248e81a0f9e0f8446cbd634040c93632b5e1268 100644 (file)
@@ -77,6 +77,9 @@
 #define IRQ_LEVEL_LOW          0x03
 #define IRQ_EDGE_BOTH          0x04
 
+#define SUN4I_FUNC_INPUT       0
+#define SUN4I_FUNC_IRQ         6
+
 struct sunxi_desc_function {
        const char      *name;
        u8              muxval;
@@ -94,6 +97,7 @@ struct sunxi_pinctrl_desc {
        int                             npins;
        unsigned                        pin_base;
        unsigned                        irq_banks;
+       bool                            irq_read_needs_mux;
 };
 
 struct sunxi_pinctrl_function {
index 97b5e4ee1ca40ae4bc5b50ab7e413833de693af7..63d4033eb683868738dedca38e838fe7e4b56cea 100644 (file)
@@ -73,7 +73,7 @@
 
 #define TIME_WINDOW_MAX_MSEC 40000
 #define TIME_WINDOW_MIN_MSEC 250
-
+#define ENERGY_UNIT_SCALE    1000 /* scale from driver unit to powercap unit */
 enum unit_type {
        ARBITRARY_UNIT, /* no translation */
        POWER_UNIT,
@@ -158,6 +158,7 @@ struct rapl_domain {
        struct rapl_power_limit rpl[NR_POWER_LIMITS];
        u64 attr_map; /* track capabilities */
        unsigned int state;
+       unsigned int domain_energy_unit;
        int package_id;
 };
 #define power_zone_to_rapl_domain(_zone) \
@@ -190,6 +191,7 @@ struct rapl_defaults {
        void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
        u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
                                bool to_raw);
+       unsigned int dram_domain_energy_unit;
 };
 static struct rapl_defaults *rapl_defaults;
 
@@ -227,7 +229,8 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 static int rapl_write_data_raw(struct rapl_domain *rd,
                        enum rapl_primitives prim,
                        unsigned long long value);
-static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
+static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+                       enum unit_type type, u64 value,
                        int to_raw);
 static void package_power_limit_irq_save(int package_id);
 
@@ -305,7 +308,9 @@ static int get_energy_counter(struct powercap_zone *power_zone, u64 *energy_raw)
 
 static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy)
 {
-       *energy = rapl_unit_xlate(0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
+       struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev);
+
+       *energy = rapl_unit_xlate(rd, 0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0);
        return 0;
 }
 
@@ -639,6 +644,11 @@ static void rapl_init_domains(struct rapl_package *rp)
                        rd->msrs[4] = MSR_DRAM_POWER_INFO;
                        rd->rpl[0].prim_id = PL1_ENABLE;
                        rd->rpl[0].name = pl1_name;
+                       rd->domain_energy_unit =
+                               rapl_defaults->dram_domain_energy_unit;
+                       if (rd->domain_energy_unit)
+                               pr_info("DRAM domain energy unit %dpj\n",
+                                       rd->domain_energy_unit);
                        break;
                }
                if (mask) {
@@ -648,11 +658,13 @@ static void rapl_init_domains(struct rapl_package *rp)
        }
 }
 
-static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
+static u64 rapl_unit_xlate(struct rapl_domain *rd, int package,
+                       enum unit_type type, u64 value,
                        int to_raw)
 {
        u64 units = 1;
        struct rapl_package *rp;
+       u64 scale = 1;
 
        rp = find_package_by_id(package);
        if (!rp)
@@ -663,7 +675,12 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
                units = rp->power_unit;
                break;
        case ENERGY_UNIT:
-               units = rp->energy_unit;
+               scale = ENERGY_UNIT_SCALE;
+               /* per domain unit takes precedence */
+               if (rd && rd->domain_energy_unit)
+                       units = rd->domain_energy_unit;
+               else
+                       units = rp->energy_unit;
                break;
        case TIME_UNIT:
                return rapl_defaults->compute_time_window(rp, value, to_raw);
@@ -673,11 +690,11 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
        };
 
        if (to_raw)
-               return div64_u64(value, units);
+               return div64_u64(value, units) * scale;
 
        value *= units;
 
-       return value;
+       return div64_u64(value, scale);
 }
 
 /* in the order of enum rapl_primitives */
@@ -773,7 +790,7 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
        final = value & rp->mask;
        final = final >> rp->shift;
        if (xlate)
-               *data = rapl_unit_xlate(rd->package_id, rp->unit, final, 0);
+               *data = rapl_unit_xlate(rd, rd->package_id, rp->unit, final, 0);
        else
                *data = final;
 
@@ -799,7 +816,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
                        "failed to read msr 0x%x on cpu %d\n", msr, cpu);
                return -EIO;
        }
-       value = rapl_unit_xlate(rd->package_id, rp->unit, value, 1);
+       value = rapl_unit_xlate(rd, rd->package_id, rp->unit, value, 1);
        msr_val &= ~rp->mask;
        msr_val |= value << rp->shift;
        if (wrmsrl_safe_on_cpu(cpu, msr, msr_val)) {
@@ -818,7 +835,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
  * calculate units differ on different CPUs.
  * We convert the units to below format based on CPUs.
  * i.e.
- * energy unit: microJoules : Represented in microJoules by default
+ * energy unit: picoJoules  : Represented in picoJoules by default
  * power unit : microWatts  : Represented in milliWatts by default
  * time unit  : microseconds: Represented in seconds by default
  */
@@ -834,7 +851,7 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
        }
 
        value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = 1000000 / (1 << value);
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
 
        value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
        rp->power_unit = 1000000 / (1 << value);
@@ -842,7 +859,7 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
        value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
        rp->time_unit = 1000000 / (1 << value);
 
-       pr_debug("Core CPU package %d energy=%duJ, time=%dus, power=%duW\n",
+       pr_debug("Core CPU package %d energy=%dpJ, time=%dus, power=%duW\n",
                rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
 
        return 0;
@@ -859,7 +876,7 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
                return -ENODEV;
        }
        value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
-       rp->energy_unit = 1 << value;
+       rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
 
        value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
        rp->power_unit = (1 << value) * 1000;
@@ -867,7 +884,7 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
        value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
        rp->time_unit = 1000000 / (1 << value);
 
-       pr_debug("Atom package %d energy=%duJ, time=%dus, power=%duW\n",
+       pr_debug("Atom package %d energy=%dpJ, time=%dus, power=%duW\n",
                rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
 
        return 0;
@@ -1017,6 +1034,13 @@ static const struct rapl_defaults rapl_defaults_core = {
        .compute_time_window = rapl_compute_time_window_core,
 };
 
+static const struct rapl_defaults rapl_defaults_hsw_server = {
+       .check_unit = rapl_check_unit_core,
+       .set_floor_freq = set_floor_freq_default,
+       .compute_time_window = rapl_compute_time_window_core,
+       .dram_domain_energy_unit = 15300,
+};
+
 static const struct rapl_defaults rapl_defaults_atom = {
        .check_unit = rapl_check_unit_atom,
        .set_floor_freq = set_floor_freq_atom,
@@ -1037,7 +1061,7 @@ static const struct x86_cpu_id rapl_ids[] = {
        RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */
        RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */
        RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */
-       RAPL_CPU(0x3f, rapl_defaults_core),/* Haswell */
+       RAPL_CPU(0x3f, rapl_defaults_hsw_server),/* Haswell servers */
        RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */
        RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */
        RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */
index b899947d839d87b03608d1f9bf4b4208cf57aa01..a4a8a6dc60c470bf6911632a8b14f790cc415ef4 100644 (file)
@@ -1839,10 +1839,12 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
        }
 
        if (rdev->ena_pin) {
-               ret = regulator_ena_gpio_ctrl(rdev, true);
-               if (ret < 0)
-                       return ret;
-               rdev->ena_gpio_state = 1;
+               if (!rdev->ena_gpio_state) {
+                       ret = regulator_ena_gpio_ctrl(rdev, true);
+                       if (ret < 0)
+                               return ret;
+                       rdev->ena_gpio_state = 1;
+               }
        } else if (rdev->desc->ops->enable) {
                ret = rdev->desc->ops->enable(rdev);
                if (ret < 0)
@@ -1939,10 +1941,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
        trace_regulator_disable(rdev_get_name(rdev));
 
        if (rdev->ena_pin) {
-               ret = regulator_ena_gpio_ctrl(rdev, false);
-               if (ret < 0)
-                       return ret;
-               rdev->ena_gpio_state = 0;
+               if (rdev->ena_gpio_state) {
+                       ret = regulator_ena_gpio_ctrl(rdev, false);
+                       if (ret < 0)
+                               return ret;
+                       rdev->ena_gpio_state = 0;
+               }
 
        } else if (rdev->desc->ops->disable) {
                ret = rdev->desc->ops->disable(rdev);
@@ -3444,13 +3448,6 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
        if (attr == &dev_attr_requested_microamps.attr)
                return rdev->desc->type == REGULATOR_CURRENT ? mode : 0;
 
-       /* all the other attributes exist to support constraints;
-        * don't show them if there are no constraints, or if the
-        * relevant supporting methods are missing.
-        */
-       if (!rdev->constraints)
-               return 0;
-
        /* constraints need specific supporting methods */
        if (attr == &dev_attr_min_microvolts.attr ||
            attr == &dev_attr_max_microvolts.attr)
@@ -3633,12 +3630,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
                                 config->ena_gpio, ret);
                        goto wash;
                }
-
-               if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
-                       rdev->ena_gpio_state = 1;
-
-               if (config->ena_gpio_invert)
-                       rdev->ena_gpio_state = !rdev->ena_gpio_state;
        }
 
        /* set regulator constraints */
@@ -3807,9 +3798,11 @@ int regulator_suspend_finish(void)
        list_for_each_entry(rdev, &regulator_list, list) {
                mutex_lock(&rdev->mutex);
                if (rdev->use_count > 0  || rdev->constraints->always_on) {
-                       error = _regulator_do_enable(rdev);
-                       if (error)
-                               ret = error;
+                       if (!_regulator_is_enabled(rdev)) {
+                               error = _regulator_do_enable(rdev);
+                               if (error)
+                                       ret = error;
+                       }
                } else {
                        if (!have_full_constraints())
                                goto unlock;
index bc6100103f7f476e7381482a404f33ea01851fad..f0489cb9018b4e7895937d330d077e100783fc16 100644 (file)
@@ -152,6 +152,15 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
        config.regmap = chip->regmap;
        config.of_node = dev->of_node;
 
+       /* Mask all interrupt sources to deassert interrupt line */
+       error = regmap_write(chip->regmap, DA9210_REG_MASK_A, ~0);
+       if (!error)
+               error = regmap_write(chip->regmap, DA9210_REG_MASK_B, ~0);
+       if (error) {
+               dev_err(&i2c->dev, "Failed to write to mask reg: %d\n", error);
+               return error;
+       }
+
        rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config);
        if (IS_ERR(rdev)) {
                dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");
index 9205f433573cc124bd84701f6ee6324969b093e9..18198316b6cf15c406c6f9eb243bc39601b97979 100644 (file)
@@ -1572,6 +1572,10 @@ static int palmas_regulators_probe(struct platform_device *pdev)
        if (!pmic)
                return -ENOMEM;
 
+       if (of_device_is_compatible(node, "ti,tps659038-pmic"))
+               palmas_generic_regs_info[PALMAS_REG_REGEN2].ctrl_addr =
+                                                       TPS659038_REGEN2_CTRL;
+
        pmic->dev = &pdev->dev;
        pmic->palmas = palmas;
        palmas->pmic = pmic;
index 1f93b752a81cdc36a824459ebf66354aea275af8..3fd44353cc80eea153fe1118c81180b5e2d21b67 100644 (file)
@@ -235,6 +235,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(0),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG2",
@@ -249,6 +250,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(1),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG3",
@@ -263,6 +265,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_BUCK4_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(2),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG4",
@@ -277,6 +280,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(3),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG5",
@@ -291,6 +295,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(4),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG6",
@@ -305,6 +310,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(5),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG7",
@@ -319,6 +325,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(6),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "LDO_REG8",
@@ -333,6 +340,7 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_LDO_VSEL_MASK,
                .enable_reg = RK808_LDO_EN_REG,
                .enable_mask = BIT(7),
+               .enable_time = 400,
                .owner = THIS_MODULE,
        }, {
                .name = "SWITCH_REG1",
index e2cffe01b8072263330b28164130cf2fd23953b5..fb991ec764235d55443a9f99414efc3511cad7a2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
index 92f6af6da6991f0f15400b07572b4338458ff8ca..73354ee278771ac0be6fc9fcaa40b96f9964bc9b 100644 (file)
@@ -951,6 +951,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
        void *bufs_va;
        int err = 0, i;
        size_t total_buf_space;
+       bool notify;
 
        vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
        if (!vrp)
@@ -1030,8 +1031,22 @@ static int rpmsg_probe(struct virtio_device *vdev)
                }
        }
 
+       /*
+        * Prepare to kick but don't notify yet - we can't do this before
+        * device is ready.
+        */
+       notify = virtqueue_kick_prepare(vrp->rvq);
+
+       /* From this point on, we can notify and get callbacks. */
+       virtio_device_ready(vdev);
+
        /* tell the remote processor it can start sending messages */
-       virtqueue_kick(vrp->rvq);
+       /*
+        * this might be concurrent with callbacks, but we are only
+        * doing notify, not a full kick here, so that's ok.
+        */
+       if (notify)
+               virtqueue_notify(vrp->rvq);
 
        dev_info(&vdev->dev, "rpmsg host is online\n");
 
index 70a5d94cc766af5302dfaf945dfb4a1a36b48236..b283a1a573b30549cb101f763ed430e258a29124 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/suspend.h>
 #include <linux/uaccess.h>
 
 #include "rtc-at91rm9200.h"
@@ -54,6 +55,10 @@ static void __iomem *at91_rtc_regs;
 static int irq;
 static DEFINE_SPINLOCK(at91_rtc_lock);
 static u32 at91_rtc_shadow_imr;
+static bool suspended;
+static DEFINE_SPINLOCK(suspended_lock);
+static unsigned long cached_events;
+static u32 at91_rtc_imr;
 
 static void at91_rtc_write_ier(u32 mask)
 {
@@ -290,7 +295,9 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
        struct rtc_device *rtc = platform_get_drvdata(pdev);
        unsigned int rtsr;
        unsigned long events = 0;
+       int ret = IRQ_NONE;
 
+       spin_lock(&suspended_lock);
        rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr();
        if (rtsr) {             /* this interrupt is shared!  Is it ours? */
                if (rtsr & AT91_RTC_ALARM)
@@ -304,14 +311,22 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
 
                at91_rtc_write(AT91_RTC_SCCR, rtsr);    /* clear status reg */
 
-               rtc_update_irq(rtc, 1, events);
+               if (!suspended) {
+                       rtc_update_irq(rtc, 1, events);
 
-               dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__,
-                       events >> 8, events & 0x000000FF);
+                       dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n",
+                               __func__, events >> 8, events & 0x000000FF);
+               } else {
+                       cached_events |= events;
+                       at91_rtc_write_idr(at91_rtc_imr);
+                       pm_system_wakeup();
+               }
 
-               return IRQ_HANDLED;
+               ret = IRQ_HANDLED;
        }
-       return IRQ_NONE;                /* not handled */
+       spin_unlock(&suspended_lock);
+
+       return ret;
 }
 
 static const struct at91_rtc_config at91rm9200_config = {
@@ -401,8 +416,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                                        AT91_RTC_CALEV);
 
        ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt,
-                               IRQF_SHARED,
-                               "at91_rtc", pdev);
+                              IRQF_SHARED | IRQF_COND_SUSPEND,
+                              "at91_rtc", pdev);
        if (ret) {
                dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
                return ret;
@@ -454,8 +469,6 @@ static void at91_rtc_shutdown(struct platform_device *pdev)
 
 /* AT91RM9200 RTC Power management control */
 
-static u32 at91_rtc_imr;
-
 static int at91_rtc_suspend(struct device *dev)
 {
        /* this IRQ is shared with DBGU and other hardware which isn't
@@ -464,21 +477,42 @@ static int at91_rtc_suspend(struct device *dev)
        at91_rtc_imr = at91_rtc_read_imr()
                        & (AT91_RTC_ALARM|AT91_RTC_SECEV);
        if (at91_rtc_imr) {
-               if (device_may_wakeup(dev))
+               if (device_may_wakeup(dev)) {
+                       unsigned long flags;
+
                        enable_irq_wake(irq);
-               else
+
+                       spin_lock_irqsave(&suspended_lock, flags);
+                       suspended = true;
+                       spin_unlock_irqrestore(&suspended_lock, flags);
+               } else {
                        at91_rtc_write_idr(at91_rtc_imr);
+               }
        }
        return 0;
 }
 
 static int at91_rtc_resume(struct device *dev)
 {
+       struct rtc_device *rtc = dev_get_drvdata(dev);
+
        if (at91_rtc_imr) {
-               if (device_may_wakeup(dev))
+               if (device_may_wakeup(dev)) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&suspended_lock, flags);
+
+                       if (cached_events) {
+                               rtc_update_irq(rtc, 1, cached_events);
+                               cached_events = 0;
+                       }
+
+                       suspended = false;
+                       spin_unlock_irqrestore(&suspended_lock, flags);
+
                        disable_irq_wake(irq);
-               else
-                       at91_rtc_write_ier(at91_rtc_imr);
+               }
+               at91_rtc_write_ier(at91_rtc_imr);
        }
        return 0;
 }
index 2183fd2750abd9d4b388ca4a5f48916600356122..5ccaee32df7223ad1aeb2d8cb74233caa7fae351 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/suspend.h>
 #include <linux/clk.h>
 
 /*
@@ -77,6 +78,9 @@ struct sam9_rtc {
        unsigned int            gpbr_offset;
        int                     irq;
        struct clk              *sclk;
+       bool                    suspended;
+       unsigned long           events;
+       spinlock_t              lock;
 };
 
 #define rtt_readl(rtc, field) \
@@ -271,14 +275,9 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
        return 0;
 }
 
-/*
- * IRQ handler for the RTC
- */
-static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+static irqreturn_t at91_rtc_cache_events(struct sam9_rtc *rtc)
 {
-       struct sam9_rtc *rtc = _rtc;
        u32 sr, mr;
-       unsigned long events = 0;
 
        /* Shared interrupt may be for another device.  Note: reading
         * SR clears it, so we must only read it in this irq handler!
@@ -290,18 +289,54 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
 
        /* alarm status */
        if (sr & AT91_RTT_ALMS)
-               events |= (RTC_AF | RTC_IRQF);
+               rtc->events |= (RTC_AF | RTC_IRQF);
 
        /* timer update/increment */
        if (sr & AT91_RTT_RTTINC)
-               events |= (RTC_UF | RTC_IRQF);
+               rtc->events |= (RTC_UF | RTC_IRQF);
+
+       return IRQ_HANDLED;
+}
+
+static void at91_rtc_flush_events(struct sam9_rtc *rtc)
+{
+       if (!rtc->events)
+               return;
 
-       rtc_update_irq(rtc->rtcdev, 1, events);
+       rtc_update_irq(rtc->rtcdev, 1, rtc->events);
+       rtc->events = 0;
 
        pr_debug("%s: num=%ld, events=0x%02lx\n", __func__,
-               events >> 8, events & 0x000000FF);
+               rtc->events >> 8, rtc->events & 0x000000FF);
+}
 
-       return IRQ_HANDLED;
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+{
+       struct sam9_rtc *rtc = _rtc;
+       int ret;
+
+       spin_lock(&rtc->lock);
+
+       ret = at91_rtc_cache_events(rtc);
+
+       /* We're called in suspended state */
+       if (rtc->suspended) {
+               /* Mask irqs coming from this peripheral */
+               rtt_writel(rtc, MR,
+                          rtt_readl(rtc, MR) &
+                          ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+               /* Trigger a system wakeup */
+               pm_system_wakeup();
+       } else {
+               at91_rtc_flush_events(rtc);
+       }
+
+       spin_unlock(&rtc->lock);
+
+       return ret;
 }
 
 static const struct rtc_class_ops at91_rtc_ops = {
@@ -421,7 +456,8 @@ static int at91_rtc_probe(struct platform_device *pdev)
 
        /* register irq handler after we know what name we'll use */
        ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
-                               IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc);
+                              IRQF_SHARED | IRQF_COND_SUSPEND,
+                              dev_name(&rtc->rtcdev->dev), rtc);
        if (ret) {
                dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq);
                return ret;
@@ -482,7 +518,12 @@ static int at91_rtc_suspend(struct device *dev)
        rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
        if (rtc->imr) {
                if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) {
+                       unsigned long flags;
+
                        enable_irq_wake(rtc->irq);
+                       spin_lock_irqsave(&rtc->lock, flags);
+                       rtc->suspended = true;
+                       spin_unlock_irqrestore(&rtc->lock, flags);
                        /* don't let RTTINC cause wakeups */
                        if (mr & AT91_RTT_RTTINCIEN)
                                rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
@@ -499,10 +540,18 @@ static int at91_rtc_resume(struct device *dev)
        u32             mr;
 
        if (rtc->imr) {
+               unsigned long flags;
+
                if (device_may_wakeup(dev))
                        disable_irq_wake(rtc->irq);
                mr = rtt_readl(rtc, MR);
                rtt_writel(rtc, MR, mr | rtc->imr);
+
+               spin_lock_irqsave(&rtc->lock, flags);
+               rtc->suspended = false;
+               at91_rtc_cache_events(rtc);
+               at91_rtc_flush_events(rtc);
+               spin_unlock_irqrestore(&rtc->lock, flags);
        }
 
        return 0;
index 8c3bfcb115b787318d0ce942c07c655f79fc1cb7..803869c7d7c206f6dbff5cc7427ea3faf8e1bf2b 100644 (file)
@@ -399,21 +399,21 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
         * of this RTC chip.  We check for it anyways in case support is
         * added in the future.
         */
-       if (unlikely((seconds >= 0xc0) && (seconds <= 0xff)))
+       if (unlikely(seconds >= 0xc0))
                alrm->time.tm_sec = -1;
        else
                alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds,
                                                       RTC_SECS_BCD_MASK,
                                                       RTC_SECS_BIN_MASK);
 
-       if (unlikely((minutes >= 0xc0) && (minutes <= 0xff)))
+       if (unlikely(minutes >= 0xc0))
                alrm->time.tm_min = -1;
        else
                alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes,
                                                       RTC_MINS_BCD_MASK,
                                                       RTC_MINS_BIN_MASK);
 
-       if (unlikely((hours >= 0xc0) && (hours <= 0xff)))
+       if (unlikely(hours >= 0xc0))
                alrm->time.tm_hour = -1;
        else
                alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours,
@@ -472,13 +472,13 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
         * field, and we only support four fields.  We put the support
         * here anyways for the future.
         */
-       if (unlikely((seconds >= 0xc0) && (seconds <= 0xff)))
+       if (unlikely(seconds >= 0xc0))
                seconds = 0xff;
 
-       if (unlikely((minutes >= 0xc0) && (minutes <= 0xff)))
+       if (unlikely(minutes >= 0xc0))
                minutes = 0xff;
 
-       if (unlikely((hours >= 0xc0) && (hours <= 0xff)))
+       if (unlikely(hours >= 0xc0))
                hours = 0xff;
 
        alrm->time.tm_mon       = -1;
@@ -528,7 +528,6 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 /* ----------------------------------------------------------------------- */
 /* /dev/rtcX Interface functions */
 
-#ifdef CONFIG_RTC_INTF_DEV
 /**
  * ds1685_rtc_alarm_irq_enable - replaces ioctl() RTC_AIE on/off.
  * @dev: pointer to device structure.
@@ -557,7 +556,6 @@ ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 
        return 0;
 }
-#endif
 /* ----------------------------------------------------------------------- */
 
 
@@ -1612,7 +1610,7 @@ ds1685_rtc_sysfs_time_regs_show(struct device *dev,
                ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
 
        /* Make sure we actually matched something. */
-       if (!bcd_reg_info && !bin_reg_info)
+       if (!bcd_reg_info || !bin_reg_info)
                return -EINVAL;
 
        /* bcd_reg_info->reg == bin_reg_info->reg. */
@@ -1650,7 +1648,7 @@ ds1685_rtc_sysfs_time_regs_store(struct device *dev,
                return -EINVAL;
 
        /* Make sure we actually matched something. */
-       if (!bcd_reg_info && !bin_reg_info)
+       if (!bcd_reg_info || !bin_reg_info)
                return -EINVAL;
 
        /* Check for a valid range. */
index e2436d140175a109907e55eacafeb1906105748d..3a6fd3a8a2ec63d389a2f4dbf948f5c2090ecc3a 100644 (file)
@@ -413,8 +413,8 @@ static void rtc_mrst_do_remove(struct device *dev)
        mrst->dev = NULL;
 }
 
-#ifdef CONFIG_PM
-static int mrst_suspend(struct device *dev, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int mrst_suspend(struct device *dev)
 {
        struct mrst_rtc *mrst = dev_get_drvdata(dev);
        unsigned char   tmp;
@@ -453,7 +453,7 @@ static int mrst_suspend(struct device *dev, pm_message_t mesg)
  */
 static inline int mrst_poweroff(struct device *dev)
 {
-       return mrst_suspend(dev, PMSG_HIBERNATE);
+       return mrst_suspend(dev);
 }
 
 static int mrst_resume(struct device *dev)
@@ -490,9 +490,11 @@ static int mrst_resume(struct device *dev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(mrst_pm_ops, mrst_suspend, mrst_resume);
+#define MRST_PM_OPS (&mrst_pm_ops)
+
 #else
-#define        mrst_suspend    NULL
-#define        mrst_resume     NULL
+#define MRST_PM_OPS NULL
 
 static inline int mrst_poweroff(struct device *dev)
 {
@@ -529,9 +531,8 @@ static struct platform_driver vrtc_mrst_platform_driver = {
        .remove         = vrtc_mrst_platform_remove,
        .shutdown       = vrtc_mrst_platform_shutdown,
        .driver = {
-               .name           = (char *) driver_name,
-               .suspend        = mrst_suspend,
-               .resume         = mrst_resume,
+               .name   = driver_name,
+               .pm     = MRST_PM_OPS,
        }
 };
 
index 4241eeab3386ab3803d4238471fd2bd92ac66226..f4cf6851fae971e34d4b43e945ac91160bcaef21 100644 (file)
@@ -849,6 +849,7 @@ static struct s3c_rtc_data const s3c2443_rtc_data = {
 
 static struct s3c_rtc_data const s3c6410_rtc_data = {
        .max_user_freq          = 32768,
+       .needs_src_clk          = true,
        .irq_handler            = s3c6410_rtc_irq,
        .set_freq               = s3c6410_rtc_setfreq,
        .enable_tick            = s3c6410_rtc_enable_tick,
index 96128cb009f352dba8497a47427dda713f608a4b..da212813f2d5dcd301a923df946daa9c481cb06f 100644 (file)
@@ -547,7 +547,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
         * parse input
         */
        num_of_segments = 0;
-       for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
+       for (i = 0; (i < count && (buf[i] != '\0') && (buf[i] != '\n')); i++) {
                for (j = i; (buf[j] != ':') &&
                        (buf[j] != '\0') &&
                        (buf[j] != '\n') &&
index 09db45296eed2c87330399abbfecdbb2f9b44014..7497ddde2dd67a28ce2e042970bebda9b3e9da5b 100644 (file)
@@ -92,7 +92,7 @@ bool scm_reserve_cluster(struct scm_request *scmrq)
                        add = 0;
                        continue;
                }
-               for (pos = 0; pos <= iter->aob->request.msb_count; pos++) {
+               for (pos = 0; pos < iter->aob->request.msb_count; pos++) {
                        if (clusters_intersect(req, iter->request[pos]) &&
                            (rq_data_dir(req) == WRITE ||
                             rq_data_dir(iter->request[pos]) == WRITE)) {
index 9219953ee949a9dfaf1ff0f044e41a3e5c13adc7..d9afc51af7d3dbc7df2e38865596ba3473a1f708 100644 (file)
@@ -6815,7 +6815,8 @@ static struct ata_port_operations ipr_sata_ops = {
 };
 
 static struct ata_port_info sata_port_info = {
-       .flags          = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
+       .flags          = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
+                         ATA_FLAG_SAS_HOST,
        .pio_mask       = ATA_PIO4_ONLY,
        .mwdma_mask     = ATA_MWDMA2,
        .udma_mask      = ATA_UDMA6,
index 932d9cc98d2fc807c4ef0e7715fe922803bbc29c..9c706d8c144174dae8cf87c1aa62a95a98f961e4 100644 (file)
@@ -547,7 +547,8 @@ static struct ata_port_operations sas_sata_ops = {
 };
 
 static struct ata_port_info sata_port_info = {
-       .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ,
+       .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ |
+                ATA_FLAG_SAS_HOST,
        .pio_mask = ATA_PIO4,
        .mwdma_mask = ATA_MWDMA2,
        .udma_mask = ATA_UDMA6,
index 62b58d38ce2e63beda6d1ba4d9876c9af2e51008..60de66252fa2b9ea168648c5097da7f8ae7f49ae 100644 (file)
@@ -500,6 +500,7 @@ static void sas_revalidate_domain(struct work_struct *work)
        struct sas_discovery_event *ev = to_sas_discovery_event(work);
        struct asd_sas_port *port = ev->port;
        struct sas_ha_struct *ha = port->ha;
+       struct domain_device *ddev = port->port_dev;
 
        /* prevent revalidation from finding sata links in recovery */
        mutex_lock(&ha->disco_mutex);
@@ -514,8 +515,9 @@ static void sas_revalidate_domain(struct work_struct *work)
        SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
                    task_pid_nr(current));
 
-       if (port->port_dev)
-               res = sas_ex_revalidate_domain(port->port_dev);
+       if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
+                    ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE))
+               res = sas_ex_revalidate_domain(ddev);
 
        SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
                    port->id, task_pid_nr(current), res);
index 99f43b7fc9ab74256d6f22f17e3c6d75c6e5fcdb..ab4879e12ea7fd0b2745327400b2166451519483 100644 (file)
@@ -1596,7 +1596,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        /*
         * Finally register the new FC Nexus with TCM
         */
-       __transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
+       transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
 
        return 0;
 }
index f3ee439d6f0e23b41bd54b0ad1bbb7941ec4e505..cd4c293f0dd0d375be6d6d815108aeb588304fec 100644 (file)
@@ -81,7 +81,9 @@ static int __init sh_pm_runtime_init(void)
                if (!of_machine_is_compatible("renesas,emev2") &&
                    !of_machine_is_compatible("renesas,r7s72100") &&
                    !of_machine_is_compatible("renesas,r8a73a4") &&
+#ifndef CONFIG_PM_GENERIC_DOMAINS_OF
                    !of_machine_is_compatible("renesas,r8a7740") &&
+#endif
                    !of_machine_is_compatible("renesas,r8a7778") &&
                    !of_machine_is_compatible("renesas,r8a7779") &&
                    !of_machine_is_compatible("renesas,r8a7790") &&
index 9af7841f2e8c6010060c17a038bc8c86c792a729..06de34001c6695a5a741925e862d7baa05853c98 100644 (file)
@@ -764,17 +764,17 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
                        (unsigned long long)xfer->rx_dma);
        }
 
-       /* REVISIT: We're waiting for ENDRX before we start the next
+       /* REVISIT: We're waiting for RXBUFF before we start the next
         * transfer because we need to handle some difficult timing
-        * issues otherwise. If we wait for ENDTX in one transfer and
-        * then starts waiting for ENDRX in the next, it's difficult
-        * to tell the difference between the ENDRX interrupt we're
-        * actually waiting for and the ENDRX interrupt of the
+        * issues otherwise. If we wait for TXBUFE in one transfer and
+        * then starts waiting for RXBUFF in the next, it's difficult
+        * to tell the difference between the RXBUFF interrupt we're
+        * actually waiting for and the RXBUFF interrupt of the
         * previous transfer.
         *
         * It should be doable, though. Just not now...
         */
-       spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
+       spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES));
        spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
 }
 
index a0197fd4e95c40b26817fe942d2069a0381a41e5..4f8c798e0633a81483c3b05af46805b1848ba386 100644 (file)
@@ -108,7 +108,8 @@ static void dw_spi_dma_tx_done(void *arg)
 {
        struct dw_spi *dws = arg;
 
-       if (test_and_clear_bit(TX_BUSY, &dws->dma_chan_busy) & BIT(RX_BUSY))
+       clear_bit(TX_BUSY, &dws->dma_chan_busy);
+       if (test_bit(RX_BUSY, &dws->dma_chan_busy))
                return;
        dw_spi_xfer_done(dws);
 }
@@ -139,6 +140,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws)
                                1,
                                DMA_MEM_TO_DEV,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!txdesc)
+               return NULL;
+
        txdesc->callback = dw_spi_dma_tx_done;
        txdesc->callback_param = dws;
 
@@ -153,7 +157,8 @@ static void dw_spi_dma_rx_done(void *arg)
 {
        struct dw_spi *dws = arg;
 
-       if (test_and_clear_bit(RX_BUSY, &dws->dma_chan_busy) & BIT(TX_BUSY))
+       clear_bit(RX_BUSY, &dws->dma_chan_busy);
+       if (test_bit(TX_BUSY, &dws->dma_chan_busy))
                return;
        dw_spi_xfer_done(dws);
 }
@@ -184,6 +189,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
                                1,
                                DMA_DEV_TO_MEM,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!rxdesc)
+               return NULL;
+
        rxdesc->callback = dw_spi_dma_rx_done;
        rxdesc->callback_param = dws;
 
index 5ba331047cbefdea6d948ca20c8d6d3898cafbb0..6d331e0db33122b23cfa17f6602618a510efcde1 100644 (file)
@@ -36,13 +36,13 @@ struct spi_pci_desc {
 
 static struct spi_pci_desc spi_pci_mid_desc_1 = {
        .setup = dw_spi_mid_init,
-       .num_cs = 32,
+       .num_cs = 5,
        .bus_num = 0,
 };
 
 static struct spi_pci_desc spi_pci_mid_desc_2 = {
        .setup = dw_spi_mid_init,
-       .num_cs = 4,
+       .num_cs = 2,
        .bus_num = 1,
 };
 
index 5a97a62b298ac1a526d4c1bde932f3eb2d5ad574..4847afba89f4e933e5a5d778c5f94e1a14ffe156 100644 (file)
@@ -621,14 +621,14 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
        if (!dws->fifo_len) {
                u32 fifo;
 
-               for (fifo = 2; fifo <= 256; fifo++) {
+               for (fifo = 1; fifo < 256; fifo++) {
                        dw_writew(dws, DW_SPI_TXFLTR, fifo);
                        if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
                                break;
                }
                dw_writew(dws, DW_SPI_TXFLTR, 0);
 
-               dws->fifo_len = (fifo == 2) ? 0 : fifo - 1;
+               dws->fifo_len = (fifo == 1) ? 0 : fifo;
                dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
        }
 }
index c01567d53581c0dcdfc6fcb61e7f6e821d0e0b39..e649bc7d4c086bb789d2dc1803c621bebdc29a19 100644 (file)
@@ -459,6 +459,13 @@ static int img_spfi_transfer_one(struct spi_master *master,
        unsigned long flags;
        int ret;
 
+       if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
+               dev_err(spfi->dev,
+                       "Transfer length (%d) is greater than the max supported (%d)",
+                       xfer->len, SPFI_TRANSACTION_TSIZE_MASK);
+               return -EINVAL;
+       }
+
        /*
         * Stop all DMA and reset the controller if the previous transaction
         * timed-out and never completed it's DMA.
index 89ca162801da10b8ec7a9c4311a33344f6a438a7..ee513a85296b19a3c57aad4daef4ec42ee3d90b1 100644 (file)
@@ -534,12 +534,12 @@ static void giveback(struct pl022 *pl022)
        pl022->cur_msg = NULL;
        pl022->cur_transfer = NULL;
        pl022->cur_chip = NULL;
-       spi_finalize_current_message(pl022->master);
 
        /* disable the SPI/SSP operation */
        writew((readw(SSP_CR1(pl022->virtbase)) &
                (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
 
+       spi_finalize_current_message(pl022->master);
 }
 
 /**
index ff9cdbdb6672371df54b6c59ce54579a46758602..2b2c359f5a501da32a38af38cfe0c0956b0e23c9 100644 (file)
@@ -498,7 +498,7 @@ static int spi_qup_probe(struct platform_device *pdev)
        struct resource *res;
        struct device *dev;
        void __iomem *base;
-       u32 max_freq, iomode;
+       u32 max_freq, iomode, num_cs;
        int ret, irq, size;
 
        dev = &pdev->dev;
@@ -550,10 +550,11 @@ static int spi_qup_probe(struct platform_device *pdev)
        }
 
        /* use num-cs unless not present or out of range */
-       if (of_property_read_u16(dev->of_node, "num-cs",
-                       &master->num_chipselect) ||
-                       (master->num_chipselect > SPI_NUM_CHIPSELECTS))
+       if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) ||
+           num_cs > SPI_NUM_CHIPSELECTS)
                master->num_chipselect = SPI_NUM_CHIPSELECTS;
+       else
+               master->num_chipselect = num_cs;
 
        master->bus_num = pdev->id;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
index 884a716e50cb822ce49dcb0e925a2c1856130bcb..5c061687035886e5768bf6031616068906540b04 100644 (file)
@@ -101,6 +101,7 @@ struct ti_qspi {
 #define QSPI_FLEN(n)                   ((n - 1) << 0)
 
 /* STATUS REGISTER */
+#define BUSY                           0x01
 #define WC                             0x02
 
 /* INTERRUPT REGISTER */
@@ -199,6 +200,21 @@ static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
        ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
 }
 
+static inline u32 qspi_is_busy(struct ti_qspi *qspi)
+{
+       u32 stat;
+       unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
+
+       stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
+       while ((stat & BUSY) && time_after(timeout, jiffies)) {
+               cpu_relax();
+               stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
+       }
+
+       WARN(stat & BUSY, "qspi busy\n");
+       return stat & BUSY;
+}
+
 static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
 {
        int wlen, count;
@@ -211,6 +227,9 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
        wlen = t->bits_per_word >> 3;   /* in bytes */
 
        while (count) {
+               if (qspi_is_busy(qspi))
+                       return -EBUSY;
+
                switch (wlen) {
                case 1:
                        dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
@@ -266,6 +285,9 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
 
        while (count) {
                dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
+               if (qspi_is_busy(qspi))
+                       return -EBUSY;
+
                ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
                if (!wait_for_completion_timeout(&qspi->transfer_complete,
                                                 QSPI_COMPLETION_TIMEOUT)) {
index c64a3e59fce30a7f9658afcca246a6d6872627da..57a195041dc72e019a02b3c7c4b6f4c2a6fac59b 100644 (file)
@@ -1105,13 +1105,14 @@ void spi_finalize_current_message(struct spi_master *master)
                                "failed to unprepare message: %d\n", ret);
                }
        }
+
+       trace_spi_message_done(mesg);
+
        master->cur_msg_prepared = false;
 
        mesg->state = NULL;
        if (mesg->complete)
                mesg->complete(mesg->context);
-
-       trace_spi_message_done(mesg);
 }
 EXPORT_SYMBOL_GPL(spi_finalize_current_message);
 
index 9800c01e6fb97409966e1b35157656ff139f31ea..3f72451d2de01aa44d1b16f633ddd8999894db25 100644 (file)
@@ -426,7 +426,6 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
                                unsigned int *data)
 {
        struct pci1710_private *devpriv = dev->private;
-       unsigned int chan = CR_CHAN(insn->chanspec);
        int ret = 0;
        int i;
 
@@ -447,7 +446,7 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
                if (ret)
                        break;
 
-               ret = pci171x_ai_read_sample(dev, s, chan, &val);
+               ret = pci171x_ai_read_sample(dev, s, 0, &val);
                if (ret)
                        break;
 
index dbdea71d6b95b5e3c25a0a2fe2deb9eb57422a94..e856f01ca07716c8acb3881bbe8e4373a64beab5 100644 (file)
@@ -91,9 +91,10 @@ unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
                        stalled++;
                        if (stalled > 10)
                                break;
+               } else {
+                       residue = new_residue;
+                       stalled = 0;
                }
-               residue = new_residue;
-               stalled = 0;
        }
        return residue;
 }
index e37118321a278466ab75f1e51294b2183551bc58..a0906685e27fcb59d9712e9b2619c9f343e5db5e 100644 (file)
@@ -103,11 +103,6 @@ enum vmk80xx_model {
        VMK8061_MODEL
 };
 
-struct firmware_version {
-       unsigned char ic3_vers[32];     /* USB-Controller */
-       unsigned char ic6_vers[32];     /* CPU */
-};
-
 static const struct comedi_lrange vmk8061_range = {
        2, {
                UNI_RANGE(5),
@@ -156,68 +151,12 @@ static const struct vmk80xx_board vmk80xx_boardinfo[] = {
 struct vmk80xx_private {
        struct usb_endpoint_descriptor *ep_rx;
        struct usb_endpoint_descriptor *ep_tx;
-       struct firmware_version fw;
        struct semaphore limit_sem;
        unsigned char *usb_rx_buf;
        unsigned char *usb_tx_buf;
        enum vmk80xx_model model;
 };
 
-static int vmk80xx_check_data_link(struct comedi_device *dev)
-{
-       struct vmk80xx_private *devpriv = dev->private;
-       struct usb_device *usb = comedi_to_usb_dev(dev);
-       unsigned int tx_pipe;
-       unsigned int rx_pipe;
-       unsigned char tx[1];
-       unsigned char rx[2];
-
-       tx_pipe = usb_sndbulkpipe(usb, 0x01);
-       rx_pipe = usb_rcvbulkpipe(usb, 0x81);
-
-       tx[0] = VMK8061_CMD_RD_PWR_STAT;
-
-       /*
-        * Check that IC6 (PIC16F871) is powered and
-        * running and the data link between IC3 and
-        * IC6 is working properly
-        */
-       usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
-       usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10);
-
-       return (int)rx[1];
-}
-
-static void vmk80xx_read_eeprom(struct comedi_device *dev, int flag)
-{
-       struct vmk80xx_private *devpriv = dev->private;
-       struct usb_device *usb = comedi_to_usb_dev(dev);
-       unsigned int tx_pipe;
-       unsigned int rx_pipe;
-       unsigned char tx[1];
-       unsigned char rx[64];
-       int cnt;
-
-       tx_pipe = usb_sndbulkpipe(usb, 0x01);
-       rx_pipe = usb_rcvbulkpipe(usb, 0x81);
-
-       tx[0] = VMK8061_CMD_RD_VERSION;
-
-       /*
-        * Read the firmware version info of IC3 and
-        * IC6 from the internal EEPROM of the IC
-        */
-       usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
-       usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10);
-
-       rx[cnt] = '\0';
-
-       if (flag & IC3_VERSION)
-               strncpy(devpriv->fw.ic3_vers, rx + 1, 24);
-       else                    /* IC6_VERSION */
-               strncpy(devpriv->fw.ic6_vers, rx + 25, 24);
-}
-
 static void vmk80xx_do_bulk_msg(struct comedi_device *dev)
 {
        struct vmk80xx_private *devpriv = dev->private;
@@ -878,16 +817,6 @@ static int vmk80xx_auto_attach(struct comedi_device *dev,
 
        usb_set_intfdata(intf, devpriv);
 
-       if (devpriv->model == VMK8061_MODEL) {
-               vmk80xx_read_eeprom(dev, IC3_VERSION);
-               dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
-
-               if (vmk80xx_check_data_link(dev)) {
-                       vmk80xx_read_eeprom(dev, IC6_VERSION);
-                       dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
-               }
-       }
-
        if (devpriv->model == VMK8055_MODEL)
                vmk80xx_reset_device(dev);
 
index 24183028bd712b11af46cd4531f60b33b4e57338..6d5b38d6957852ee81caa09cb6e3c047c55d26b8 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 d9d6fad7cb00725f43142967bad4ca6b39a32b06..816174388f13347447c495700e3dad85e7c269db 100644 (file)
@@ -214,11 +214,17 @@ struct mxs_lradc {
        unsigned long           is_divided;
 
        /*
-        * Touchscreen LRADC channels receives a private slot in the CTRL4
-        * register, the slot #7. Therefore only 7 slots instead of 8 in the
-        * CTRL4 register can be mapped to LRADC channels when using the
-        * touchscreen.
-        *
+        * When the touchscreen is enabled, we give it two private virtual
+        * channels: #6 and #7. This means that only 6 virtual channels (instead
+        * of 8) will be available for buffered capture.
+        */
+#define TOUCHSCREEN_VCHANNEL1          7
+#define TOUCHSCREEN_VCHANNEL2          6
+#define BUFFER_VCHANS_LIMITED          0x3f
+#define BUFFER_VCHANS_ALL              0xff
+       u8                      buffer_vchans;
+
+       /*
         * Furthermore, certain LRADC channels are shared between touchscreen
         * and/or touch-buttons and generic LRADC block. Therefore when using
         * either of these, these channels are not available for the regular
@@ -342,6 +348,9 @@ struct mxs_lradc {
 #define        LRADC_CTRL4                             0x140
 #define        LRADC_CTRL4_LRADCSELECT_MASK(n)         (0xf << ((n) * 4))
 #define        LRADC_CTRL4_LRADCSELECT_OFFSET(n)       ((n) * 4)
+#define        LRADC_CTRL4_LRADCSELECT(n, x) \
+                               (((x) << LRADC_CTRL4_LRADCSELECT_OFFSET(n)) & \
+                               LRADC_CTRL4_LRADCSELECT_MASK(n))
 
 #define LRADC_RESOLUTION                       12
 #define LRADC_SINGLE_SAMPLE_MASK               ((1 << LRADC_RESOLUTION) - 1)
@@ -416,6 +425,14 @@ static bool mxs_lradc_check_touch_event(struct mxs_lradc *lradc)
                                        LRADC_STATUS_TOUCH_DETECT_RAW);
 }
 
+static void mxs_lradc_map_channel(struct mxs_lradc *lradc, unsigned vch,
+                                 unsigned ch)
+{
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(vch),
+                               LRADC_CTRL4);
+       mxs_lradc_reg_set(lradc, LRADC_CTRL4_LRADCSELECT(vch, ch), LRADC_CTRL4);
+}
+
 static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
 {
        /*
@@ -450,12 +467,8 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
                LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
                        LRADC_DELAY(3));
 
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
-                       LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
-                       LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch), LRADC_CTRL1);
 
-       /* wake us again, when the complete conversion is done */
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch), LRADC_CTRL1);
        /*
         * after changing the touchscreen plates setting
         * the signals need some initial time to settle. Start the
@@ -509,12 +522,8 @@ static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1,
                LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
                                        LRADC_DELAY(3));
 
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
-                       LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
-                       LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch2), LRADC_CTRL1);
 
-       /* wake us again, when the conversions are done */
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch2), LRADC_CTRL1);
        /*
         * after changing the touchscreen plates setting
         * the signals need some initial time to settle. Start the
@@ -580,36 +589,6 @@ static unsigned mxs_lradc_read_ts_pressure(struct mxs_lradc *lradc,
 #define TS_CH_XM 4
 #define TS_CH_YM 5
 
-static int mxs_lradc_read_ts_channel(struct mxs_lradc *lradc)
-{
-       u32 reg;
-       int val;
-
-       reg = readl(lradc->base + LRADC_CTRL1);
-
-       /* only channels 3 to 5 are of interest here */
-       if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YP)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YP) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_YP), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_YP);
-       } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_XM)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_XM) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_XM), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_XM);
-       } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YM)) {
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YM) |
-                       LRADC_CTRL1_LRADC_IRQ(TS_CH_YM), LRADC_CTRL1);
-               val = mxs_lradc_read_raw_channel(lradc, TS_CH_YM);
-       } else {
-               return -EIO;
-       }
-
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
-
-       return val;
-}
-
 /*
  * YP(open)--+-------------+
  *           |             |--+
@@ -653,7 +632,8 @@ static void mxs_lradc_prepare_x_pos(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_X;
-       mxs_lradc_setup_ts_channel(lradc, TS_CH_YP);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YP);
+       mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
 }
 
 /*
@@ -674,7 +654,8 @@ static void mxs_lradc_prepare_y_pos(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_Y;
-       mxs_lradc_setup_ts_channel(lradc, TS_CH_XM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_XM);
+       mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
 }
 
 /*
@@ -695,7 +676,10 @@ static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0);
 
        lradc->cur_plate = LRADC_SAMPLE_PRESSURE;
-       mxs_lradc_setup_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YM);
+       mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL2, TS_CH_XP);
+       mxs_lradc_setup_ts_pressure(lradc, TOUCHSCREEN_VCHANNEL2,
+                                               TOUCHSCREEN_VCHANNEL1);
 }
 
 static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
@@ -708,6 +692,19 @@ static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
        mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
 }
 
+static void mxs_lradc_start_touch_event(struct mxs_lradc *lradc)
+{
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+                               LRADC_CTRL1);
+       mxs_lradc_reg_set(lradc,
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
+       /*
+        * start with the Y-pos, because it uses nearly the same plate
+        * settings like the touch detection
+        */
+       mxs_lradc_prepare_y_pos(lradc);
+}
+
 static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc)
 {
        input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos);
@@ -725,10 +722,12 @@ static void mxs_lradc_complete_touch_event(struct mxs_lradc *lradc)
         * start a dummy conversion to burn time to settle the signals
         * note: we are not interested in the conversion's value
         */
-       mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(5));
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
-       mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(5), LRADC_CTRL1);
-       mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << 5) |
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(TOUCHSCREEN_VCHANNEL1));
+       mxs_lradc_reg_clear(lradc,
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
+       mxs_lradc_reg_wrt(lradc,
+               LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
                LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */
                        LRADC_DELAY(2));
 }
@@ -760,59 +759,45 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid)
 
        /* if it is released, wait for the next touch via IRQ */
        lradc->cur_plate = LRADC_TOUCH;
-       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1);
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
+       mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
+       mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ |
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
        mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
 }
 
 /* touchscreen's state machine */
 static void mxs_lradc_handle_touch(struct mxs_lradc *lradc)
 {
-       int val;
-
        switch (lradc->cur_plate) {
        case LRADC_TOUCH:
-               /*
-                * start with the Y-pos, because it uses nearly the same plate
-                * settings like the touch detection
-                */
-               if (mxs_lradc_check_touch_event(lradc)) {
-                       mxs_lradc_reg_clear(lradc,
-                                       LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
-                                       LRADC_CTRL1);
-                       mxs_lradc_prepare_y_pos(lradc);
-               }
+               if (mxs_lradc_check_touch_event(lradc))
+                       mxs_lradc_start_touch_event(lradc);
                mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ,
                                        LRADC_CTRL1);
                return;
 
        case LRADC_SAMPLE_Y:
-               val = mxs_lradc_read_ts_channel(lradc);
-               if (val < 0) {
-                       mxs_lradc_enable_touch_detection(lradc); /* re-start */
-                       return;
-               }
-               lradc->ts_y_pos = val;
+               lradc->ts_y_pos = mxs_lradc_read_raw_channel(lradc,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_prepare_x_pos(lradc);
                return;
 
        case LRADC_SAMPLE_X:
-               val = mxs_lradc_read_ts_channel(lradc);
-               if (val < 0) {
-                       mxs_lradc_enable_touch_detection(lradc); /* re-start */
-                       return;
-               }
-               lradc->ts_x_pos = val;
+               lradc->ts_x_pos = mxs_lradc_read_raw_channel(lradc,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_prepare_pressure(lradc);
                return;
 
        case LRADC_SAMPLE_PRESSURE:
-               lradc->ts_pressure =
-                       mxs_lradc_read_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
+               lradc->ts_pressure = mxs_lradc_read_ts_pressure(lradc,
+                                                       TOUCHSCREEN_VCHANNEL2,
+                                                       TOUCHSCREEN_VCHANNEL1);
                mxs_lradc_complete_touch_event(lradc);
                return;
 
        case LRADC_SAMPLE_VALID:
-               val = mxs_lradc_read_ts_channel(lradc); /* ignore the value */
                mxs_lradc_finish_touch_event(lradc, 1);
                break;
        }
@@ -844,9 +829,9 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val)
         * used if doing raw sampling.
         */
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
+               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0),
                        LRADC_CTRL1);
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+       mxs_lradc_reg_clear(lradc, 0x1, LRADC_CTRL0);
 
        /* Enable / disable the divider per requirement */
        if (test_bit(chan, &lradc->is_divided))
@@ -1090,9 +1075,8 @@ static void mxs_lradc_disable_ts(struct mxs_lradc *lradc)
 {
        /* stop all interrupts from firing */
        mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
-               LRADC_CTRL1_LRADC_IRQ_EN(2) | LRADC_CTRL1_LRADC_IRQ_EN(3) |
-               LRADC_CTRL1_LRADC_IRQ_EN(4) | LRADC_CTRL1_LRADC_IRQ_EN(5),
-               LRADC_CTRL1);
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
 
        /* Power-down touchscreen touch-detect circuitry. */
        mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
@@ -1158,26 +1142,31 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
        struct iio_dev *iio = data;
        struct mxs_lradc *lradc = iio_priv(iio);
        unsigned long reg = readl(lradc->base + LRADC_CTRL1);
+       uint32_t clr_irq = mxs_lradc_irq_mask(lradc);
        const uint32_t ts_irq_mask =
                LRADC_CTRL1_TOUCH_DETECT_IRQ |
-               LRADC_CTRL1_LRADC_IRQ(2) |
-               LRADC_CTRL1_LRADC_IRQ(3) |
-               LRADC_CTRL1_LRADC_IRQ(4) |
-               LRADC_CTRL1_LRADC_IRQ(5);
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
 
        if (!(reg & mxs_lradc_irq_mask(lradc)))
                return IRQ_NONE;
 
-       if (lradc->use_touchscreen && (reg & ts_irq_mask))
+       if (lradc->use_touchscreen && (reg & ts_irq_mask)) {
                mxs_lradc_handle_touch(lradc);
 
-       if (iio_buffer_enabled(iio))
-               iio_trigger_poll(iio->trig);
-       else if (reg & LRADC_CTRL1_LRADC_IRQ(0))
+               /* Make sure we don't clear the next conversion's interrupt. */
+               clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+                               LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));
+       }
+
+       if (iio_buffer_enabled(iio)) {
+               if (reg & lradc->buffer_vchans)
+                       iio_trigger_poll(iio->trig);
+       } else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) {
                complete(&lradc->completion);
+       }
 
-       mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc),
-                       LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1);
 
        return IRQ_HANDLED;
 }
@@ -1289,9 +1278,10 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
        }
 
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
-                                                       LRADC_CTRL1);
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+               mxs_lradc_reg_clear(lradc,
+                       lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+                       LRADC_CTRL1);
+       mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
 
        for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
                ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
@@ -1324,10 +1314,11 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio)
        mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK |
                                        LRADC_DELAY_KICK, LRADC_DELAY(0));
 
-       mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
+       mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
        if (lradc->soc == IMX28_LRADC)
-               mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
-                                       LRADC_CTRL1);
+               mxs_lradc_reg_clear(lradc,
+                       lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+                       LRADC_CTRL1);
 
        kfree(lradc->buffer);
        mutex_unlock(&lradc->lock);
@@ -1353,7 +1344,7 @@ static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio,
        if (lradc->use_touchbutton)
                rsvd_chans++;
        if (lradc->use_touchscreen)
-               rsvd_chans++;
+               rsvd_chans += 2;
 
        /* Test for attempts to map channels with special mode of operation. */
        if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS))
@@ -1413,6 +1404,13 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
                .channel = 8,
                .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
        },
+       /* Hidden channel to keep indexes */
+       {
+               .type = IIO_TEMP,
+               .indexed = 1,
+               .scan_index = -1,
+               .channel = 9,
+       },
        MXS_ADC_CHAN(10, IIO_VOLTAGE),  /* VDDIO */
        MXS_ADC_CHAN(11, IIO_VOLTAGE),  /* VTH */
        MXS_ADC_CHAN(12, IIO_VOLTAGE),  /* VDDA */
@@ -1583,6 +1581,11 @@ static int mxs_lradc_probe(struct platform_device *pdev)
 
        touch_ret = mxs_lradc_probe_touchscreen(lradc, node);
 
+       if (touch_ret == 0)
+               lradc->buffer_vchans = BUFFER_VCHANS_LIMITED;
+       else
+               lradc->buffer_vchans = BUFFER_VCHANS_ALL;
+
        /* Grab all IRQ sources */
        for (i = 0; i < of_cfg->irq_count; i++) {
                lradc->irq[i] = platform_get_irq(pdev, i);
index fd171d8b38fbcc444f3e7118bb66b2d51bdf698c..90cc18b703cf67ae6c089c36d51d8ebde6f28106 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 017d2f8379b78ca86f7e30ed0e85855684c7b6ec..c17893b4918c82bf176e9ecfac235cd6439e7763 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -68,7 +69,7 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev,
                break;
        case IIO_ANGL_VEL:
                vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
-               vel = (vel << 4) >> 4;
+               vel = sign_extend32(vel, 11);
                *val = vel;
                break;
        default:
index 4324282afe499bc83f32318873a6cd484875df1b..03b2a90b9ac0b6f73109686b66623c61f0cd5ccb 100644 (file)
@@ -330,16 +330,6 @@ static void device_init_registers(struct vnt_private *pDevice)
        /* zonetype initial */
        pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
 
-       /* Get RFType */
-       pDevice->byRFType = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RFTYPE);
-
-       /* force change RevID for VT3253 emu */
-       if ((pDevice->byRFType & RF_EMU) != 0)
-                       pDevice->byRevId = 0x80;
-
-       pDevice->byRFType &= RF_MASK;
-       pr_debug("pDevice->byRFType = %x\n", pDevice->byRFType);
-
        if (!pDevice->bZoneRegExist)
                pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
 
@@ -1187,12 +1177,14 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        PSTxDesc head_td;
-       u32 dma_idx = TYPE_AC0DMA;
+       u32 dma_idx;
        unsigned long flags;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (!ieee80211_is_data(hdr->frame_control))
+       if (ieee80211_is_data(hdr->frame_control))
+               dma_idx = TYPE_AC0DMA;
+       else
                dma_idx = TYPE_TXDMA0;
 
        if (AVAIL_TD(priv, dma_idx) < 1) {
@@ -1206,6 +1198,9 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->pTDInfo->skb = skb;
 
+       if (dma_idx == TYPE_AC0DMA)
+               head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
+
        priv->iTDUsed[dma_idx]++;
 
        /* Take ownership */
@@ -1234,13 +1229,10 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma);
 
-       if (dma_idx == TYPE_AC0DMA) {
-               head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
-
+       if (head_td->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)
                MACvTransmitAC0(priv->PortOffset);
-       } else {
+       else
                MACvTransmit0(priv->PortOffset);
-       }
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1778,6 +1770,12 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
        MACvInitialize(priv->PortOffset);
        MACvReadEtherAddress(priv->PortOffset, priv->abyCurrentNetAddr);
 
+       /* Get RFType */
+       priv->byRFType = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_RFTYPE);
+       priv->byRFType &= RF_MASK;
+
+       dev_dbg(&pcid->dev, "RF Type = %x\n", priv->byRFType);
+
        device_get_options(priv);
        device_set_options(priv);
        /* Mask out the options cannot be set to the chip */
index 941b2adca95a9d8fbb01bf2afe8a4c99cd1b04fb..7626f635f160799f581b50d3e1e50bbcc7fd8da0 100644 (file)
@@ -794,6 +794,7 @@ bool RFbSetPower(
                break;
        case RATE_6M:
        case RATE_9M:
+       case RATE_12M:
        case RATE_18M:
                byPwr = priv->abyOFDMPwrTbl[uCH];
                if (priv->byRFType == RF_UW2452)
index c42cde59f598efe27f8bff760ce94ca20692a177..c4286ccac32034558966cc52b7fac8501ecc5daa 100644 (file)
@@ -640,6 +640,7 @@ int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel)
                break;
        case RATE_6M:
        case RATE_9M:
+       case RATE_12M:
        case RATE_18M:
        case RATE_24M:
        case RATE_36M:
index 50bad55a0c42e3bd9eef6925520cb1e9bddf2209..2accb6e47beb35c1eff10256f7a85d749fe6d590 100644 (file)
@@ -4256,11 +4256,17 @@ int iscsit_close_connection(
        pr_debug("Closing iSCSI connection CID %hu on SID:"
                " %u\n", conn->cid, sess->sid);
        /*
-        * Always up conn_logout_comp just in case the RX Thread is sleeping
-        * and the logout response never got sent because the connection
-        * failed.
+        * Always up conn_logout_comp for the traditional TCP case just in case
+        * the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout
+        * response never got sent because the connection failed.
+        *
+        * However for iser-target, isert_wait4logout() is using conn_logout_comp
+        * to signal logout response TX interrupt completion.  Go ahead and skip
+        * this for iser since isert_rx_opcode() does not wait on logout failure,
+        * and to avoid iscsi_conn pointer dereference in iser-target code.
         */
-       complete(&conn->conn_logout_comp);
+       if (conn->conn_transport->transport_type == ISCSI_TCP)
+               complete(&conn->conn_logout_comp);
 
        iscsi_release_thread_set(conn);
 
index 1c197bad6132be98cd267b6ea666fc24e41e00a9..bdd8731a4daa677083d829333fc651591ebca046 100644 (file)
@@ -22,7 +22,6 @@
 #include <target/target_core_fabric.h>
 
 #include <target/iscsi/iscsi_target_core.h>
-#include <target/iscsi/iscsi_transport.h>
 #include "iscsi_target_seq_pdu_list.h"
 #include "iscsi_target_tq.h"
 #include "iscsi_target_erl0.h"
@@ -940,8 +939,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
 
        if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
                spin_unlock_bh(&conn->state_lock);
-               if (conn->conn_transport->transport_type == ISCSI_TCP)
-                       iscsit_close_connection(conn);
+               iscsit_close_connection(conn);
                return;
        }
 
index 6b3c329546895ab1095beb5c048ef24c6e1cea19..c36bd7c29136aba1ea42afbc28cae34c6c7ad6a8 100644 (file)
@@ -953,11 +953,8 @@ static int tcm_loop_make_nexus(
                transport_free_session(tl_nexus->se_sess);
                goto out;
        }
-       /*
-        * Now, register the SAS I_T Nexus as active with the call to
-        * transport_register_session()
-        */
-       __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
+       /* Now, register the SAS I_T Nexus as active. */
+       transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
                        tl_nexus->se_sess, tl_nexus);
        tl_tpg->tl_nexus = tl_nexus;
        pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated"
index 58f49ff69b1424bf5feb33ed64eba495d8826851..79b4ec3ca2db12416a692fba785a09b462e3169f 100644 (file)
@@ -650,6 +650,18 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
        return aligned_max_sectors;
 }
 
+bool se_dev_check_wce(struct se_device *dev)
+{
+       bool wce = false;
+
+       if (dev->transport->get_write_cache)
+               wce = dev->transport->get_write_cache(dev);
+       else if (dev->dev_attrib.emulate_write_cache > 0)
+               wce = true;
+
+       return wce;
+}
+
 int se_dev_set_max_unmap_lba_count(
        struct se_device *dev,
        u32 max_unmap_lba_count)
@@ -767,6 +779,16 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
                pr_err("Illegal value %d\n", flag);
                return -EINVAL;
        }
+       if (flag &&
+           dev->transport->get_write_cache) {
+               pr_err("emulate_fua_write not supported for this device\n");
+               return -EINVAL;
+       }
+       if (dev->export_count) {
+               pr_err("emulate_fua_write cannot be changed with active"
+                      " exports: %d\n", dev->export_count);
+               return -EINVAL;
+       }
        dev->dev_attrib.emulate_fua_write = flag;
        pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n",
                        dev, dev->dev_attrib.emulate_fua_write);
@@ -801,7 +823,11 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
                pr_err("emulate_write_cache not supported for this device\n");
                return -EINVAL;
        }
-
+       if (dev->export_count) {
+               pr_err("emulate_write_cache cannot be changed with active"
+                      " exports: %d\n", dev->export_count);
+               return -EINVAL;
+       }
        dev->dev_attrib.emulate_write_cache = flag;
        pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
                        dev, dev->dev_attrib.emulate_write_cache);
@@ -1534,8 +1560,6 @@ int target_configure_device(struct se_device *dev)
        ret = dev->transport->configure_device(dev);
        if (ret)
                goto out;
-       dev->dev_flags |= DF_CONFIGURED;
-
        /*
         * XXX: there is not much point to have two different values here..
         */
@@ -1597,6 +1621,8 @@ int target_configure_device(struct se_device *dev)
        list_add_tail(&dev->g_dev_node, &g_device_list);
        mutex_unlock(&g_device_mutex);
 
+       dev->dev_flags |= DF_CONFIGURED;
+
        return 0;
 
 out_free_alua:
index 1045dcd7bf651b679ee355a19401065d559976b1..f6c954c4635f5dab27ac24ea117dd284561c836a 100644 (file)
@@ -1121,7 +1121,7 @@ static u32 pscsi_get_device_type(struct se_device *dev)
        struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
        struct scsi_device *sd = pdv->pdv_sd;
 
-       return sd->type;
+       return (sd) ? sd->type : TYPE_NO_LUN;
 }
 
 static sector_t pscsi_get_blocks(struct se_device *dev)
index 9a2f9d3a6e70514ad9351ab6e144709e8b95f91d..3e729741111075cf4828a46ac2f434414e70faf1 100644 (file)
@@ -708,8 +708,7 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
                }
        }
        if (cdb[1] & 0x8) {
-               if (!dev->dev_attrib.emulate_fua_write ||
-                   !dev->dev_attrib.emulate_write_cache) {
+               if (!dev->dev_attrib.emulate_fua_write || !se_dev_check_wce(dev)) {
                        pr_err("Got CDB: 0x%02x with FUA bit set, but device"
                               " does not advertise support for FUA write\n",
                               cdb[0]);
index 460e9310947399661ce1fbd6ab4ed3e86b4a47e1..6c8bd6bc175ca48fb9d33063dc3f3b8185d19876 100644 (file)
@@ -454,19 +454,6 @@ check_scsi_name:
 }
 EXPORT_SYMBOL(spc_emulate_evpd_83);
 
-static bool
-spc_check_dev_wce(struct se_device *dev)
-{
-       bool wce = false;
-
-       if (dev->transport->get_write_cache)
-               wce = dev->transport->get_write_cache(dev);
-       else if (dev->dev_attrib.emulate_write_cache > 0)
-               wce = true;
-
-       return wce;
-}
-
 /* Extended INQUIRY Data VPD Page */
 static sense_reason_t
 spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
@@ -490,7 +477,7 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
        buf[5] = 0x07;
 
        /* If WriteCache emulation is enabled, set V_SUP */
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                buf[6] = 0x01;
        /* If an LBA map is present set R_SUP */
        spin_lock(&cmd->se_dev->t10_alua.lba_map_lock);
@@ -897,7 +884,7 @@ static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p)
        if (pc == 1)
                goto out;
 
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                p[2] = 0x04; /* Write Cache Enable */
        p[12] = 0x20; /* Disabled Read Ahead */
 
@@ -1009,7 +996,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
             (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
                spc_modesense_write_protect(&buf[length], type);
 
-       if ((spc_check_dev_wce(dev)) &&
+       if ((se_dev_check_wce(dev)) &&
            (dev->dev_attrib.emulate_fua_write > 0))
                spc_modesense_dpofua(&buf[length], type);
 
index 0adc0f6502134eb3292a7a2cab66ac75be4d6406..ac3cbabdbdf0243ecbfd91c01e331ee3e0013a1a 100644 (file)
@@ -2389,6 +2389,10 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
        list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
 out:
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+       if (ret && ack_kref)
+               target_put_sess_cmd(se_sess, se_cmd);
+
        return ret;
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
index 97b486c3dda136a21824d02ea0f70c828b214d46..583e755d809177d59953b991a9c8dd9068649205 100644 (file)
@@ -359,7 +359,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                ep = fc_seq_exch(seq);
                if (ep) {
                        lport = ep->lp;
-                       if (lport && (ep->xid <= lport->lro_xid))
+                       if (lport && (ep->xid <= lport->lro_xid)) {
                                /*
                                 * "ddp_done" trigger invalidation of HW
                                 * specific DDP context
@@ -374,6 +374,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                                 * identified using ep->xid)
                                 */
                                cmd->was_ddp_setup = 0;
+                       }
                }
        }
 }
index 25d244cbbe8fda719658e35be8f2081ee0f5989f..031018e7a65bd72a4ec8ba3a452e16f455e5f3a1 100644 (file)
@@ -262,13 +262,12 @@ static int int3400_thermal_probe(struct platform_device *pdev)
        result = acpi_parse_art(priv->adev->handle, &priv->art_count,
                                &priv->arts, true);
        if (result)
-               goto free_priv;
-
+               dev_dbg(&pdev->dev, "_ART table parsing error\n");
 
        result = acpi_parse_trt(priv->adev->handle, &priv->trt_count,
                                &priv->trts, true);
        if (result)
-               goto free_art;
+               dev_dbg(&pdev->dev, "_TRT table parsing error\n");
 
        platform_set_drvdata(pdev, priv);
 
@@ -281,7 +280,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)
                                                &int3400_thermal_params, 0, 0);
        if (IS_ERR(priv->thermal)) {
                result = PTR_ERR(priv->thermal);
-               goto free_trt;
+               goto free_art_trt;
        }
 
        priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add(
@@ -295,9 +294,8 @@ static int int3400_thermal_probe(struct platform_device *pdev)
 
 free_zone:
        thermal_zone_device_unregister(priv->thermal);
-free_trt:
+free_art_trt:
        kfree(priv->trts);
-free_art:
        kfree(priv->arts);
 free_priv:
        kfree(priv);
index f88b0887702568578a5d288f925ab1c5b08e7a97..1e25133d35e2cbe8e7476a382bd27433a5801b0c 100644 (file)
@@ -208,7 +208,7 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
                                trip_cnt, GFP_KERNEL);
                if (!int34x_thermal_zone->aux_trips) {
                        ret = -ENOMEM;
-                       goto free_mem;
+                       goto err_trip_alloc;
                }
                trip_mask = BIT(trip_cnt) - 1;
                int34x_thermal_zone->aux_trip_nr = trip_cnt;
@@ -248,14 +248,15 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
                                                0, 0);
        if (IS_ERR(int34x_thermal_zone->zone)) {
                ret = PTR_ERR(int34x_thermal_zone->zone);
-               goto free_lpat;
+               goto err_thermal_zone;
        }
 
        return int34x_thermal_zone;
 
-free_lpat:
+err_thermal_zone:
        acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
-free_mem:
+       kfree(int34x_thermal_zone->aux_trips);
+err_trip_alloc:
        kfree(int34x_thermal_zone);
        return ERR_PTR(ret);
 }
@@ -266,6 +267,7 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone
 {
        thermal_zone_device_unregister(int34x_thermal_zone->zone);
        acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
+       kfree(int34x_thermal_zone->aux_trips);
        kfree(int34x_thermal_zone);
 }
 EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
index 6ceebd659dd400423c0640b1d0911da36b441b74..12623bc02f46679674d9bd1c3f1574fc21b57c37 100644 (file)
@@ -688,6 +688,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = {
        { X86_VENDOR_INTEL, 6, 0x45},
        { X86_VENDOR_INTEL, 6, 0x46},
        { X86_VENDOR_INTEL, 6, 0x4c},
+       { X86_VENDOR_INTEL, 6, 0x4d},
        { X86_VENDOR_INTEL, 6, 0x56},
        {}
 };
index 2580a4872f90febeb5af00136e16054bb59e4903..fe4e767018c4cf73afa3c53852b6d48191e2a81e 100644 (file)
@@ -387,21 +387,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (irq) {
-               int ret;
-
                /*
                 * platform has IRQ support.
                 * Then, driver uses common registers
-                */
-
-               ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
-                                      dev_name(dev), common);
-               if (ret) {
-                       dev_err(dev, "irq request failed\n ");
-                       return ret;
-               }
-
-               /*
                 * rcar_has_irq_support() will be enabled
                 */
                res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
@@ -456,8 +444,16 @@ static int rcar_thermal_probe(struct platform_device *pdev)
        }
 
        /* enable temperature comparation */
-       if (irq)
+       if (irq) {
+               ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
+                                      dev_name(dev), common);
+               if (ret) {
+                       dev_err(dev, "irq request failed\n ");
+                       goto error_unregister;
+               }
+
                rcar_thermal_common_write(common, ENR, enr_bits);
+       }
 
        platform_set_drvdata(pdev, common);
 
@@ -467,9 +463,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 
 error_unregister:
        rcar_thermal_for_each_priv(priv, common) {
-               thermal_zone_device_unregister(priv->zone);
                if (rcar_has_irq_support(priv))
                        rcar_thermal_irq_disable(priv);
+               thermal_zone_device_unregister(priv->zone);
        }
 
        pm_runtime_put(dev);
@@ -485,9 +481,9 @@ static int rcar_thermal_remove(struct platform_device *pdev)
        struct rcar_thermal_priv *priv;
 
        rcar_thermal_for_each_priv(priv, common) {
-               thermal_zone_device_unregister(priv->zone);
                if (rcar_has_irq_support(priv))
                        rcar_thermal_irq_disable(priv);
+               thermal_zone_device_unregister(priv->zone);
        }
 
        pm_runtime_put(dev);
index 933cd80a6bc5693e23da36048461bfd6250ba40b..1d30b0975651547bdc1464befd517eb450957fc0 100644 (file)
@@ -682,6 +682,7 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on)
 
        if (on) {
                con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
+               con |= (1 << EXYNOS7_PD_DET_EN_SHIFT);
                interrupt_en =
                        (of_thermal_is_trip_valid(tz, 7)
                        << EXYNOS7_TMU_INTEN_RISE7_SHIFT) |
@@ -704,9 +705,9 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on)
                        interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
        } else {
                con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
+               con &= ~(1 << EXYNOS7_PD_DET_EN_SHIFT);
                interrupt_en = 0; /* Disable all interrupts */
        }
-       con |= 1 << EXYNOS7_PD_DET_EN_SHIFT;
 
        writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN);
        writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
@@ -918,34 +919,16 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
 }
 
 static const struct of_device_id exynos_tmu_match[] = {
-       {
-               .compatible = "samsung,exynos3250-tmu",
-       },
-       {
-               .compatible = "samsung,exynos4210-tmu",
-       },
-       {
-               .compatible = "samsung,exynos4412-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5250-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5260-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5420-tmu",
-       },
-       {
-               .compatible = "samsung,exynos5420-tmu-ext-triminfo",
-       },
-       {
-               .compatible = "samsung,exynos5440-tmu",
-       },
-       {
-               .compatible = "samsung,exynos7-tmu",
-       },
-       {},
+       { .compatible = "samsung,exynos3250-tmu", },
+       { .compatible = "samsung,exynos4210-tmu", },
+       { .compatible = "samsung,exynos4412-tmu", },
+       { .compatible = "samsung,exynos5250-tmu", },
+       { .compatible = "samsung,exynos5260-tmu", },
+       { .compatible = "samsung,exynos5420-tmu", },
+       { .compatible = "samsung,exynos5420-tmu-ext-triminfo", },
+       { .compatible = "samsung,exynos5440-tmu", },
+       { .compatible = "samsung,exynos7-tmu", },
+       { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, exynos_tmu_match);
 
index 48491d1a81d650f1d10812c1fb8d5e05ff99cbe1..174d3bcf8bd7a16a161cdf94c53e8d14efaa55a6 100644 (file)
@@ -899,6 +899,22 @@ thermal_cooling_device_trip_point_show(struct device *dev,
                return sprintf(buf, "%d\n", instance->trip);
 }
 
+static struct attribute *cooling_device_attrs[] = {
+       &dev_attr_cdev_type.attr,
+       &dev_attr_max_state.attr,
+       &dev_attr_cur_state.attr,
+       NULL,
+};
+
+static const struct attribute_group cooling_device_attr_group = {
+       .attrs = cooling_device_attrs,
+};
+
+static const struct attribute_group *cooling_device_attr_groups[] = {
+       &cooling_device_attr_group,
+       NULL,
+};
+
 /* Device management */
 
 /**
@@ -1130,6 +1146,7 @@ __thermal_cooling_device_register(struct device_node *np,
        cdev->ops = ops;
        cdev->updated = false;
        cdev->device.class = &thermal_class;
+       cdev->device.groups = cooling_device_attr_groups;
        cdev->devdata = devdata;
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
        result = device_register(&cdev->device);
@@ -1139,21 +1156,6 @@ __thermal_cooling_device_register(struct device_node *np,
                return ERR_PTR(result);
        }
 
-       /* sys I/F */
-       if (type) {
-               result = device_create_file(&cdev->device, &dev_attr_cdev_type);
-               if (result)
-                       goto unregister;
-       }
-
-       result = device_create_file(&cdev->device, &dev_attr_max_state);
-       if (result)
-               goto unregister;
-
-       result = device_create_file(&cdev->device, &dev_attr_cur_state);
-       if (result)
-               goto unregister;
-
        /* Add 'this' new cdev to the global cdev list */
        mutex_lock(&thermal_list_lock);
        list_add(&cdev->node, &thermal_cdev_list);
@@ -1163,11 +1165,6 @@ __thermal_cooling_device_register(struct device_node *np,
        bind_cdev(cdev);
 
        return cdev;
-
-unregister:
-       release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
-       device_unregister(&cdev->device);
-       return ERR_PTR(result);
 }
 
 /**
index 634b6ce0e63ace5757c06513b45ac563dcfab593..62a5d449c38805019db7d554e6c0f7f43d215341 100644 (file)
@@ -1402,7 +1402,7 @@ int ti_bandgap_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
 {
        int i;
index 3fb054a10f6a0fde450e29a98ee4cdf90e18f6c7..a38c1756442aa2611e0e207466aabba4e72b94cc 100644 (file)
@@ -429,7 +429,7 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
 
        data = ti_bandgap_get_sensor_data(bgp, id);
 
-       if (data && data->cool_dev)
+       if (data)
                cpufreq_cooling_unregister(data->cool_dev);
 
        return 0;
index d7b198c400c755487309cf6e6d9b615c9cfe4a69..ce24182f851479ab61372d1091840696cfe6857f 100644 (file)
@@ -210,18 +210,6 @@ bfin_jc_chars_in_buffer(struct tty_struct *tty)
        return circ_cnt(&bfin_jc_write_buf);
 }
 
-static void
-bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       unsigned long expire = jiffies + timeout;
-       while (!circ_empty(&bfin_jc_write_buf)) {
-               if (signal_pending(current))
-                       break;
-               if (time_after(jiffies, expire))
-                       break;
-       }
-}
-
 static const struct tty_operations bfin_jc_ops = {
        .open            = bfin_jc_open,
        .close           = bfin_jc_close,
@@ -230,7 +218,6 @@ static const struct tty_operations bfin_jc_ops = {
        .flush_chars     = bfin_jc_flush_chars,
        .write_room      = bfin_jc_write_room,
        .chars_in_buffer = bfin_jc_chars_in_buffer,
-       .wait_until_sent = bfin_jc_wait_until_sent,
 };
 
 static int __init bfin_jc_init(void)
index e3b9570a1eff8aa467ec7dabbe93369c47940e87..deae122c9c4bac6a2bb28d6bbc191bfc18d16747 100644 (file)
@@ -2138,8 +2138,8 @@ int serial8250_do_startup(struct uart_port *port)
        /*
         * Clear the interrupt registers.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_LSR);
+       serial_port_in(port, UART_RX);
        serial_port_in(port, UART_IIR);
        serial_port_in(port, UART_MSR);
 
@@ -2300,8 +2300,8 @@ dont_test_tx_en:
         * saved flags to avoid getting false values from polling
         * routines or the previous session.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_LSR);
+       serial_port_in(port, UART_RX);
        serial_port_in(port, UART_IIR);
        serial_port_in(port, UART_MSR);
        up->lsr_saved_flags = 0;
@@ -2394,8 +2394,7 @@ void serial8250_do_shutdown(struct uart_port *port)
         * Read data port to reset things, and then unlink from
         * the IRQ chain.
         */
-       if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
-               serial_port_in(port, UART_RX);
+       serial_port_in(port, UART_RX);
        serial8250_rpm_put(up);
 
        del_timer_sync(&up->timer);
index e60116235836498e5b20ce56219b7d8c949acd25..6ae5b8560e4d764cafb8143a8a4654a81bf21f83 100644 (file)
@@ -59,6 +59,8 @@ struct dw8250_data {
        u8                      usr_reg;
        int                     last_mcr;
        int                     line;
+       int                     msr_mask_on;
+       int                     msr_mask_off;
        struct clk              *clk;
        struct clk              *pclk;
        struct reset_control    *rst;
@@ -81,6 +83,12 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
                value &= ~UART_MSR_DCTS;
        }
 
+       /* Override any modem control signals if needed */
+       if (offset == UART_MSR) {
+               value |= d->msr_mask_on;
+               value &= ~d->msr_mask_off;
+       }
+
        return value;
 }
 
@@ -111,7 +119,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
                        dw8250_force_idle(p);
                        writeb(value, p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 
@@ -155,7 +166,10 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
                        __raw_writeq(value & 0xff,
                                     p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 #endif /* CONFIG_64BIT */
@@ -179,7 +193,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
                        dw8250_force_idle(p);
                        writel(value, p->membase + (UART_LCR << p->regshift));
                }
-               dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+               /*
+                * FIXME: this deadlocks if port->lock is already held
+                * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+                */
        }
 }
 
@@ -334,6 +351,30 @@ static int dw8250_probe_of(struct uart_port *p,
        if (id >= 0)
                p->line = id;
 
+       if (of_property_read_bool(np, "dcd-override")) {
+               /* Always report DCD as active */
+               data->msr_mask_on |= UART_MSR_DCD;
+               data->msr_mask_off |= UART_MSR_DDCD;
+       }
+
+       if (of_property_read_bool(np, "dsr-override")) {
+               /* Always report DSR as active */
+               data->msr_mask_on |= UART_MSR_DSR;
+               data->msr_mask_off |= UART_MSR_DDSR;
+       }
+
+       if (of_property_read_bool(np, "cts-override")) {
+               /* Always report DSR as active */
+               data->msr_mask_on |= UART_MSR_DSR;
+               data->msr_mask_off |= UART_MSR_DDSR;
+       }
+
+       if (of_property_read_bool(np, "ri-override")) {
+               /* Always report Ring indicator as inactive */
+               data->msr_mask_off |= UART_MSR_RI;
+               data->msr_mask_off |= UART_MSR_TERI;
+       }
+
        /* clock got configured through clk api, all done */
        if (p->uartclk)
                return 0;
index daf2c82984e95d94d806b175bc59944ac1cd9713..892eb32cdef4bd98586d02e2e432c38aea512797 100644 (file)
@@ -69,7 +69,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
               "Please send the output of lspci -vv, this\n"
               "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
               "manufacturer and name of serial board or\n"
-              "modem board to rmk+serial@arm.linux.org.uk.\n",
+              "modem board to <linux-serial@vger.kernel.org>.\n",
               pci_name(dev), str, dev->vendor, dev->device,
               dev->subsystem_vendor, dev->subsystem_device);
 }
@@ -1987,13 +1987,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = byt_serial_setup,
        },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_QRK_UART,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = PCI_DEVICE_ID_INTEL_BSW_UART1,
@@ -2199,13 +2192,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
        /*
         * PLX
         */
-       {
-               .vendor         = PCI_VENDOR_ID_PLX,
-               .device         = PCI_DEVICE_ID_PLX_9030,
-               .subvendor      = PCI_SUBVENDOR_ID_PERLE,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pci_default_setup,
-       },
        {
                .vendor         = PCI_VENDOR_ID_PLX,
                .device         = PCI_DEVICE_ID_PLX_9050,
@@ -5415,10 +5401,6 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_b0_bt_2_115200 },
 
-       {       PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S,
-               PCI_ANY_ID, PCI_ANY_ID,
-               0, 0, pbn_b0_bt_2_115200 },
-
        {       PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_wch384_4 },
index 846552bff67d6f005c3966e80368134dcd9ab27f..4e959c43f6804d12f8677d916e1f050bdc740457 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/err.h>
 #include <linux/irq.h>
+#include <linux/suspend.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -173,6 +174,12 @@ struct atmel_uart_port {
        bool                    ms_irq_enabled;
        bool                    is_usart;       /* usart or uart */
        struct timer_list       uart_timer;     /* uart timer */
+
+       bool                    suspended;
+       unsigned int            pending;
+       unsigned int            pending_status;
+       spinlock_t              lock_suspended;
+
        int (*prepare_rx)(struct uart_port *port);
        int (*prepare_tx)(struct uart_port *port);
        void (*schedule_rx)(struct uart_port *port);
@@ -1179,12 +1186,15 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       unsigned int status, pending, pass_counter = 0;
+       unsigned int status, pending, mask, pass_counter = 0;
        bool gpio_handled = false;
 
+       spin_lock(&atmel_port->lock_suspended);
+
        do {
                status = atmel_get_lines_status(port);
-               pending = status & UART_GET_IMR(port);
+               mask = UART_GET_IMR(port);
+               pending = status & mask;
                if (!gpio_handled) {
                        /*
                         * Dealing with GPIO interrupt
@@ -1206,11 +1216,21 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
                if (!pending)
                        break;
 
+               if (atmel_port->suspended) {
+                       atmel_port->pending |= pending;
+                       atmel_port->pending_status = status;
+                       UART_PUT_IDR(port, mask);
+                       pm_system_wakeup();
+                       break;
+               }
+
                atmel_handle_receive(port, pending);
                atmel_handle_status(port, pending, status);
                atmel_handle_transmit(port, pending);
        } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
 
+       spin_unlock(&atmel_port->lock_suspended);
+
        return pass_counter ? IRQ_HANDLED : IRQ_NONE;
 }
 
@@ -1742,7 +1762,8 @@ static int atmel_startup(struct uart_port *port)
        /*
         * Allocate the IRQ
         */
-       retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
+       retval = request_irq(port->irq, atmel_interrupt,
+                       IRQF_SHARED | IRQF_COND_SUSPEND,
                        tty ? tty->name : "atmel_serial", port);
        if (retval) {
                dev_err(port->dev, "atmel_startup - Can't get irq\n");
@@ -2513,8 +2534,14 @@ static int atmel_serial_suspend(struct platform_device *pdev,
 
        /* we can not wake up if we're running on slow clock */
        atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
-       if (atmel_serial_clk_will_stop())
+       if (atmel_serial_clk_will_stop()) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&atmel_port->lock_suspended, flags);
+               atmel_port->suspended = true;
+               spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
                device_set_wakeup_enable(&pdev->dev, 0);
+       }
 
        uart_suspend_port(&atmel_uart, port);
 
@@ -2525,6 +2552,18 @@ static int atmel_serial_resume(struct platform_device *pdev)
 {
        struct uart_port *port = platform_get_drvdata(pdev);
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned long flags;
+
+       spin_lock_irqsave(&atmel_port->lock_suspended, flags);
+       if (atmel_port->pending) {
+               atmel_handle_receive(port, atmel_port->pending);
+               atmel_handle_status(port, atmel_port->pending,
+                                   atmel_port->pending_status);
+               atmel_handle_transmit(port, atmel_port->pending);
+               atmel_port->pending = 0;
+       }
+       atmel_port->suspended = false;
+       spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
 
        uart_resume_port(&atmel_uart, port);
        device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
@@ -2593,6 +2632,8 @@ static int atmel_serial_probe(struct platform_device *pdev)
        port->backup_imr = 0;
        port->uart.line = ret;
 
+       spin_lock_init(&port->lock_suspended);
+
        ret = atmel_init_gpios(port, &pdev->dev);
        if (ret < 0)
                dev_err(&pdev->dev, "%s",
index b1893f3f88f1c6b6fdb2e8e42ad565ba23e18fd1..3ad1458bfeb0fc32afe790b2aa0f3e36961b7b45 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 7ff61e24a195cbca54d60aaefd65bbdf3d0af187..33fb94f7896773c53141ec283f15a3a18be96f1a 100644 (file)
@@ -133,10 +133,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
        if (of_find_property(np, "no-loopback-test", NULL))
                port->flags |= UPF_SKIP_TEST;
 
-       ret = of_alias_get_id(np, "serial");
-       if (ret >= 0)
-               port->line = ret;
-
        port->dev = &ofdev->dev;
 
        switch (type) {
index af821a9087204ec654f637a617513ba06d68a0ef..cf08876922f1446e55a2d8ca79bf87e0d4e24fed 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 594b63331ef40e42fa75a87cde1c139a46014398..bca975f5093b73fd5ebf3e0f4ec8c42e97dfea35 100644 (file)
@@ -293,8 +293,10 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
 
        ims = serial_in(port, SPRD_IMSR);
 
-       if (!ims)
+       if (!ims) {
+               spin_unlock(&port->lock);
                return IRQ_NONE;
+       }
 
        serial_out(port, SPRD_ICLR, ~0);
 
index 51f066aa375e64789e03b9a527679e3a0a7e1c8d..2bb4dfc028734079f29a89bfb779bfdc7e0079eb 100644 (file)
@@ -1028,8 +1028,8 @@ EXPORT_SYMBOL(start_tty);
 /* We limit tty time update visibility to every 8 seconds or so. */
 static void tty_update_time(struct timespec *time)
 {
-       unsigned long sec = get_seconds() & ~7;
-       if ((long)(sec - time->tv_sec) > 0)
+       unsigned long sec = get_seconds();
+       if (abs(sec - time->tv_sec) & ~7)
                time->tv_sec = sec;
 }
 
index a5cf253b2544f001a775f93a7905e63475f7eb7e..632fc815206169281af9aa13f6ca345eb846eabe 100644 (file)
@@ -217,11 +217,17 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
 #endif
        if (!timeout)
                timeout = MAX_SCHEDULE_TIMEOUT;
-       if (wait_event_interruptible_timeout(tty->write_wait,
-                       !tty_chars_in_buffer(tty), timeout) >= 0) {
-               if (tty->ops->wait_until_sent)
-                       tty->ops->wait_until_sent(tty, timeout);
-       }
+
+       timeout = wait_event_interruptible_timeout(tty->write_wait,
+                       !tty_chars_in_buffer(tty), timeout);
+       if (timeout <= 0)
+               return;
+
+       if (timeout == MAX_SCHEDULE_TIMEOUT)
+               timeout = 0;
+
+       if (tty->ops->wait_until_sent)
+               tty->ops->wait_until_sent(tty, timeout);
 }
 EXPORT_SYMBOL(tty_wait_until_sent);
 
index ff451048c1aca26d14cd23a40b344810134695cf..4bfb7ac0239f9b4bac46ec3246ff99f29e4dcc2a 100644 (file)
@@ -929,6 +929,13 @@ __acquires(hwep->lock)
        return retval;
 }
 
+static int otg_a_alt_hnp_support(struct ci_hdrc *ci)
+{
+       dev_warn(&ci->gadget.dev,
+               "connect the device to an alternate port if you want HNP\n");
+       return isr_setup_status_phase(ci);
+}
+
 /**
  * isr_setup_packet_handler: setup packet handler
  * @ci: UDC descriptor
@@ -1061,6 +1068,10 @@ __acquires(ci->lock)
                                                        ci);
                                }
                                break;
+                       case USB_DEVICE_A_ALT_HNP_SUPPORT:
+                               if (ci_otg_is_fsm_mode(ci))
+                                       err = otg_a_alt_hnp_support(ci);
+                               break;
                        default:
                                goto delegate;
                        }
index e78720b59d67e66adebff9594475b124341b0608..683617714e7cf852fdf3fc2d4ec8590ab6d1a114 100644 (file)
@@ -1650,6 +1650,8 @@ static int acm_reset_resume(struct usb_interface *intf)
 
 static const struct usb_device_id acm_ids[] = {
        /* quirky and broken devices */
+       { USB_DEVICE(0x076d, 0x0006), /* Denso Cradle CU-321 */
+       .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
        { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
        .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
        { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
index c6b35b77dab73a173eb08d2522d4d961bebc7163..61d538aa23466b62ddf37eec8567460ecf0cd363 100644 (file)
@@ -150,9 +150,9 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
                break;
        case OTG_STATE_B_PERIPHERAL:
                otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 1);
                otg_loc_sof(fsm, 0);
                otg_set_protocol(fsm, PROTO_GADGET);
+               otg_loc_conn(fsm, 1);
                break;
        case OTG_STATE_B_WAIT_ACON:
                otg_chrg_vbus(fsm, 0);
@@ -213,10 +213,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 
                break;
        case OTG_STATE_A_PERIPHERAL:
-               otg_loc_conn(fsm, 1);
                otg_loc_sof(fsm, 0);
                otg_set_protocol(fsm, PROTO_GADGET);
                otg_drv_vbus(fsm, 1);
+               otg_loc_conn(fsm, 1);
                otg_add_timer(fsm, A_BIDL_ADIS);
                break;
        case OTG_STATE_A_WAIT_VFALL:
index 66abdbcfbfa55c08c4989d5ce4fe16b087486a79..11635537c052cdc5d4e4c78d615a09aafc4c5e83 100644 (file)
@@ -501,6 +501,7 @@ static void async_completed(struct urb *urb)
        as->status = urb->status;
        signr = as->signr;
        if (signr) {
+               memset(&sinfo, 0, sizeof(sinfo));
                sinfo.si_signo = as->signr;
                sinfo.si_errno = as->status;
                sinfo.si_code = SI_ASYNCIO;
@@ -2382,6 +2383,7 @@ static void usbdev_remove(struct usb_device *udev)
                wake_up_all(&ps->wait);
                list_del_init(&ps->list);
                if (ps->discsignr) {
+                       memset(&sinfo, 0, sizeof(sinfo));
                        sinfo.si_signo = ps->discsignr;
                        sinfo.si_errno = EPIPE;
                        sinfo.si_code = SI_ASYNCIO;
index 02e3e2d4ea5658c0ddd6de8b1cb1729425a3c0ab..6cf047878dbae1812d19c27b13d5d5a1ce71536a 100644 (file)
@@ -377,6 +377,9 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
                dwc2_is_host_mode(hsotg) ? "Host" : "Device",
                dwc2_op_state_str(hsotg));
 
+       if (hsotg->op_state == OTG_STATE_A_HOST)
+               dwc2_hcd_disconnect(hsotg);
+
        /* Change to L3 (OFF) state */
        hsotg->lx_state = DWC2_L3;
 
index 172d64e585b61b014f3333ef200d2cb2ba48958d..52e0c4e5e48efa8cc1ccecf0ee30364ff1419634 100644 (file)
@@ -205,6 +205,18 @@ static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value)
                                                omap->irq0_offset, value);
 }
 
+static void dwc3_omap_write_irqmisc_clr(struct dwc3_omap *omap, u32 value)
+{
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_MISC +
+                                               omap->irqmisc_offset, value);
+}
+
+static void dwc3_omap_write_irq0_clr(struct dwc3_omap *omap, u32 value)
+{
+       dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_0 -
+                                               omap->irq0_offset, value);
+}
+
 static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
        enum omap_dwc3_vbus_id_status status)
 {
@@ -345,9 +357,23 @@ static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
 
 static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
 {
+       u32                     reg;
+
        /* disable all IRQs */
-       dwc3_omap_write_irqmisc_set(omap, 0x00);
-       dwc3_omap_write_irq0_set(omap, 0x00);
+       reg = USBOTGSS_IRQO_COREIRQ_ST;
+       dwc3_omap_write_irq0_clr(omap, reg);
+
+       reg = (USBOTGSS_IRQMISC_OEVT |
+                       USBOTGSS_IRQMISC_DRVVBUS_RISE |
+                       USBOTGSS_IRQMISC_CHRGVBUS_RISE |
+                       USBOTGSS_IRQMISC_DISCHRGVBUS_RISE |
+                       USBOTGSS_IRQMISC_IDPULLUP_RISE |
+                       USBOTGSS_IRQMISC_DRVVBUS_FALL |
+                       USBOTGSS_IRQMISC_CHRGVBUS_FALL |
+                       USBOTGSS_IRQMISC_DISCHRGVBUS_FALL |
+                       USBOTGSS_IRQMISC_IDPULLUP_FALL);
+
+       dwc3_omap_write_irqmisc_clr(omap, reg);
 }
 
 static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
index 75648145dc1b686a89cae9f8d4de451b71ef376a..c42765b3a060bc6b28b0f7a55f0231489afe651c 100644 (file)
@@ -1161,7 +1161,6 @@ static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc,
        if (desc->opts_mutex)
                mutex_lock(desc->opts_mutex);
        memcpy(desc->ext_compat_id, page, l);
-       desc->ext_compat_id[l] = '\0';
 
        if (desc->opts_mutex)
                mutex_unlock(desc->opts_mutex);
@@ -1192,7 +1191,6 @@ static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc,
        if (desc->opts_mutex)
                mutex_lock(desc->opts_mutex);
        memcpy(desc->ext_compat_id + 8, page, l);
-       desc->ext_compat_id[l + 8] = '\0';
 
        if (desc->opts_mutex)
                mutex_unlock(desc->opts_mutex);
index af98b096af2fde060aea8978005e8ea620762566..175c9956cbe3a36949526029103d38b4c97225c3 100644 (file)
@@ -144,10 +144,9 @@ struct ffs_io_data {
        bool read;
 
        struct kiocb *kiocb;
-       const struct iovec *iovec;
-       unsigned long nr_segs;
-       char __user *buf;
-       size_t len;
+       struct iov_iter data;
+       const void *to_free;
+       char *buf;
 
        struct mm_struct *mm;
        struct work_struct work;
@@ -649,29 +648,10 @@ static void ffs_user_copy_worker(struct work_struct *work)
                                         io_data->req->actual;
 
        if (io_data->read && ret > 0) {
-               int i;
-               size_t pos = 0;
-
-               /*
-                * Since req->length may be bigger than io_data->len (after
-                * being rounded up to maxpacketsize), we may end up with more
-                * data then user space has space for.
-                */
-               ret = min_t(int, ret, io_data->len);
-
                use_mm(io_data->mm);
-               for (i = 0; i < io_data->nr_segs; i++) {
-                       size_t len = min_t(size_t, ret - pos,
-                                       io_data->iovec[i].iov_len);
-                       if (!len)
-                               break;
-                       if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
-                                                &io_data->buf[pos], len))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       pos += len;
-               }
+               ret = copy_to_iter(io_data->buf, ret, &io_data->data);
+               if (iov_iter_count(&io_data->data))
+                       ret = -EFAULT;
                unuse_mm(io_data->mm);
        }
 
@@ -684,7 +664,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
 
        io_data->kiocb->private = NULL;
        if (io_data->read)
-               kfree(io_data->iovec);
+               kfree(io_data->to_free);
        kfree(io_data->buf);
        kfree(io_data);
 }
@@ -743,6 +723,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                 * before the waiting completes, so do not assign to 'gadget' earlier
                 */
                struct usb_gadget *gadget = epfile->ffs->gadget;
+               size_t copied;
 
                spin_lock_irq(&epfile->ffs->eps_lock);
                /* In the meantime, endpoint got disabled or changed. */
@@ -750,34 +731,21 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                        spin_unlock_irq(&epfile->ffs->eps_lock);
                        return -ESHUTDOWN;
                }
+               data_len = iov_iter_count(&io_data->data);
                /*
                 * Controller may require buffer size to be aligned to
                 * maxpacketsize of an out endpoint.
                 */
-               data_len = io_data->read ?
-                          usb_ep_align_maybe(gadget, ep->ep, io_data->len) :
-                          io_data->len;
+               if (io_data->read)
+                       data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
                spin_unlock_irq(&epfile->ffs->eps_lock);
 
                data = kmalloc(data_len, GFP_KERNEL);
                if (unlikely(!data))
                        return -ENOMEM;
-               if (io_data->aio && !io_data->read) {
-                       int i;
-                       size_t pos = 0;
-                       for (i = 0; i < io_data->nr_segs; i++) {
-                               if (unlikely(copy_from_user(&data[pos],
-                                            io_data->iovec[i].iov_base,
-                                            io_data->iovec[i].iov_len))) {
-                                       ret = -EFAULT;
-                                       goto error;
-                               }
-                               pos += io_data->iovec[i].iov_len;
-                       }
-               } else {
-                       if (!io_data->read &&
-                           unlikely(__copy_from_user(data, io_data->buf,
-                                                     io_data->len))) {
+               if (!io_data->read) {
+                       copied = copy_from_iter(data, data_len, &io_data->data);
+                       if (copied != data_len) {
                                ret = -EFAULT;
                                goto error;
                        }
@@ -876,10 +844,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                                 */
                                ret = ep->status;
                                if (io_data->read && ret > 0) {
-                                       ret = min_t(size_t, ret, io_data->len);
-
-                                       if (unlikely(copy_to_user(io_data->buf,
-                                               data, ret)))
+                                       ret = copy_to_iter(data, ret, &io_data->data);
+                                       if (unlikely(iov_iter_count(&io_data->data)))
                                                ret = -EFAULT;
                                }
                        }
@@ -898,37 +864,6 @@ error:
        return ret;
 }
 
-static ssize_t
-ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
-                loff_t *ptr)
-{
-       struct ffs_io_data io_data;
-
-       ENTER();
-
-       io_data.aio = false;
-       io_data.read = false;
-       io_data.buf = (char * __user)buf;
-       io_data.len = len;
-
-       return ffs_epfile_io(file, &io_data);
-}
-
-static ssize_t
-ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ffs_io_data io_data;
-
-       ENTER();
-
-       io_data.aio = false;
-       io_data.read = true;
-       io_data.buf = buf;
-       io_data.len = len;
-
-       return ffs_epfile_io(file, &io_data);
-}
-
 static int
 ffs_epfile_open(struct inode *inode, struct file *file)
 {
@@ -965,67 +900,86 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
        return value;
 }
 
-static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb,
-                                   const struct iovec *iovec,
-                                   unsigned long nr_segs, loff_t loff)
+static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 {
-       struct ffs_io_data *io_data;
+       struct ffs_io_data io_data, *p = &io_data;
+       ssize_t res;
 
        ENTER();
 
-       io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
-       if (unlikely(!io_data))
-               return -ENOMEM;
+       if (!is_sync_kiocb(kiocb)) {
+               p = kmalloc(sizeof(io_data), GFP_KERNEL);
+               if (unlikely(!p))
+                       return -ENOMEM;
+               p->aio = true;
+       } else {
+               p->aio = false;
+       }
 
-       io_data->aio = true;
-       io_data->read = false;
-       io_data->kiocb = kiocb;
-       io_data->iovec = iovec;
-       io_data->nr_segs = nr_segs;
-       io_data->len = kiocb->ki_nbytes;
-       io_data->mm = current->mm;
+       p->read = false;
+       p->kiocb = kiocb;
+       p->data = *from;
+       p->mm = current->mm;
 
-       kiocb->private = io_data;
+       kiocb->private = p;
 
        kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
-       return ffs_epfile_io(kiocb->ki_filp, io_data);
+       res = ffs_epfile_io(kiocb->ki_filp, p);
+       if (res == -EIOCBQUEUED)
+               return res;
+       if (p->aio)
+               kfree(p);
+       else
+               *from = p->data;
+       return res;
 }
 
-static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb,
-                                  const struct iovec *iovec,
-                                  unsigned long nr_segs, loff_t loff)
+static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 {
-       struct ffs_io_data *io_data;
-       struct iovec *iovec_copy;
+       struct ffs_io_data io_data, *p = &io_data;
+       ssize_t res;
 
        ENTER();
 
-       iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL);
-       if (unlikely(!iovec_copy))
-               return -ENOMEM;
-
-       memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs);
-
-       io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
-       if (unlikely(!io_data)) {
-               kfree(iovec_copy);
-               return -ENOMEM;
+       if (!is_sync_kiocb(kiocb)) {
+               p = kmalloc(sizeof(io_data), GFP_KERNEL);
+               if (unlikely(!p))
+                       return -ENOMEM;
+               p->aio = true;
+       } else {
+               p->aio = false;
        }
 
-       io_data->aio = true;
-       io_data->read = true;
-       io_data->kiocb = kiocb;
-       io_data->iovec = iovec_copy;
-       io_data->nr_segs = nr_segs;
-       io_data->len = kiocb->ki_nbytes;
-       io_data->mm = current->mm;
+       p->read = true;
+       p->kiocb = kiocb;
+       if (p->aio) {
+               p->to_free = dup_iter(&p->data, to, GFP_KERNEL);
+               if (!p->to_free) {
+                       kfree(p);
+                       return -ENOMEM;
+               }
+       } else {
+               p->data = *to;
+               p->to_free = NULL;
+       }
+       p->mm = current->mm;
 
-       kiocb->private = io_data;
+       kiocb->private = p;
 
        kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
-       return ffs_epfile_io(kiocb->ki_filp, io_data);
+       res = ffs_epfile_io(kiocb->ki_filp, p);
+       if (res == -EIOCBQUEUED)
+               return res;
+
+       if (p->aio) {
+               kfree(p->to_free);
+               kfree(p);
+       } else {
+               *to = p->data;
+       }
+       return res;
 }
 
 static int
@@ -1105,10 +1059,10 @@ static const struct file_operations ffs_epfile_operations = {
        .llseek =       no_llseek,
 
        .open =         ffs_epfile_open,
-       .write =        ffs_epfile_write,
-       .read =         ffs_epfile_read,
-       .aio_write =    ffs_epfile_aio_write,
-       .aio_read =     ffs_epfile_aio_read,
+       .write =        new_sync_write,
+       .read =         new_sync_read,
+       .write_iter =   ffs_epfile_write_iter,
+       .read_iter =    ffs_epfile_read_iter,
        .release =      ffs_epfile_release,
        .unlocked_ioctl =       ffs_epfile_ioctl,
 };
index 426d69a9c018a0a651beac78ce63709c4b283613..a2612fb79eff261ee336b73940f88e7514f9c5e0 100644 (file)
@@ -569,7 +569,7 @@ fail:
        return status;
 }
 
-const struct file_operations f_hidg_fops = {
+static const struct file_operations f_hidg_fops = {
        .owner          = THIS_MODULE,
        .open           = f_hidg_open,
        .release        = f_hidg_release,
index 298b46112b1a354eaa2965edc548b10b628ac577..39f49f1ad22f287e58df631077a9a1506381707b 100644 (file)
@@ -289,8 +289,7 @@ static void disable_loopback(struct f_loopback *loop)
        struct usb_composite_dev        *cdev;
 
        cdev = loop->function.config->cdev;
-       disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL, NULL,
-                       NULL);
+       disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
        VDBG(cdev, "%s disabled\n", loop->function.name);
 }
 
index c89e96cfa3e47b95d179d06910d528710e59d5de..c0c3ef272714b58ea4980ba25cf24076b502a105 100644 (file)
@@ -417,7 +417,10 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        return -EINVAL;
 
                spin_lock(&port->lock);
-               __pn_reset(f);
+
+               if (fp->in_ep->driver_data)
+                       __pn_reset(f);
+
                if (alt == 1) {
                        int i;
 
index e07c50ced64ddc09256b271f72a5baacfc3b8f18..3a5ae9900b1ee585881aa8233065ef9772de8da7 100644 (file)
 #include "gadget_chips.h"
 #include "u_f.h"
 
-#define USB_MS_TO_SS_INTERVAL(x) USB_MS_TO_HS_INTERVAL(x)
-
-enum eptype {
-       EP_CONTROL = 0,
-       EP_BULK,
-       EP_ISOC,
-       EP_INTERRUPT,
-};
-
 /*
  * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
  * controller drivers.
@@ -64,8 +55,6 @@ struct f_sourcesink {
        struct usb_ep           *out_ep;
        struct usb_ep           *iso_in_ep;
        struct usb_ep           *iso_out_ep;
-       struct usb_ep           *int_in_ep;
-       struct usb_ep           *int_out_ep;
        int                     cur_alt;
 };
 
@@ -79,10 +68,6 @@ static unsigned isoc_interval;
 static unsigned isoc_maxpacket;
 static unsigned isoc_mult;
 static unsigned isoc_maxburst;
-static unsigned int_interval; /* In ms */
-static unsigned int_maxpacket;
-static unsigned int_mult;
-static unsigned int_maxburst;
 static unsigned buflen;
 
 /*-------------------------------------------------------------------------*/
@@ -107,16 +92,6 @@ static struct usb_interface_descriptor source_sink_intf_alt1 = {
        /* .iInterface          = DYNAMIC */
 };
 
-static struct usb_interface_descriptor source_sink_intf_alt2 = {
-       .bLength =              USB_DT_INTERFACE_SIZE,
-       .bDescriptorType =      USB_DT_INTERFACE,
-
-       .bAlternateSetting =    2,
-       .bNumEndpoints =        2,
-       .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
-       /* .iInterface          = DYNAMIC */
-};
-
 /* full speed support: */
 
 static struct usb_endpoint_descriptor fs_source_desc = {
@@ -155,26 +130,6 @@ static struct usb_endpoint_descriptor fs_iso_sink_desc = {
        .bInterval =            4,
 };
 
-static struct usb_endpoint_descriptor fs_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(64),
-       .bInterval =            GZERO_INT_INTERVAL,
-};
-
-static struct usb_endpoint_descriptor fs_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(64),
-       .bInterval =            GZERO_INT_INTERVAL,
-};
-
 static struct usb_descriptor_header *fs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &fs_sink_desc,
@@ -185,10 +140,6 @@ static struct usb_descriptor_header *fs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &fs_source_desc,
        (struct usb_descriptor_header *) &fs_iso_sink_desc,
        (struct usb_descriptor_header *) &fs_iso_source_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define FS_ALT_IFC_2_OFFSET    8
-       (struct usb_descriptor_header *) &fs_int_sink_desc,
-       (struct usb_descriptor_header *) &fs_int_source_desc,
        NULL,
 };
 
@@ -228,24 +179,6 @@ static struct usb_endpoint_descriptor hs_iso_sink_desc = {
        .bInterval =            4,
 };
 
-static struct usb_endpoint_descriptor hs_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-static struct usb_endpoint_descriptor hs_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_HS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
 static struct usb_descriptor_header *hs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &hs_source_desc,
@@ -256,10 +189,6 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = {
        (struct usb_descriptor_header *) &hs_sink_desc,
        (struct usb_descriptor_header *) &hs_iso_source_desc,
        (struct usb_descriptor_header *) &hs_iso_sink_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define HS_ALT_IFC_2_OFFSET    8
-       (struct usb_descriptor_header *) &hs_int_source_desc,
-       (struct usb_descriptor_header *) &hs_int_sink_desc,
        NULL,
 };
 
@@ -335,42 +264,6 @@ static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
        .wBytesPerInterval =    cpu_to_le16(1024),
 };
 
-static struct usb_endpoint_descriptor ss_int_source_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-struct usb_ss_ep_comp_descriptor ss_int_source_comp_desc = {
-       .bLength =              USB_DT_SS_EP_COMP_SIZE,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       .bMaxBurst =            0,
-       .bmAttributes =         0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
-};
-
-static struct usb_endpoint_descriptor ss_int_sink_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-
-       .bmAttributes =         USB_ENDPOINT_XFER_INT,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-       .bInterval =            USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL),
-};
-
-struct usb_ss_ep_comp_descriptor ss_int_sink_comp_desc = {
-       .bLength =              USB_DT_SS_EP_COMP_SIZE,
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-
-       .bMaxBurst =            0,
-       .bmAttributes =         0,
-       .wBytesPerInterval =    cpu_to_le16(1024),
-};
-
 static struct usb_descriptor_header *ss_source_sink_descs[] = {
        (struct usb_descriptor_header *) &source_sink_intf_alt0,
        (struct usb_descriptor_header *) &ss_source_desc,
@@ -387,12 +280,6 @@ static struct usb_descriptor_header *ss_source_sink_descs[] = {
        (struct usb_descriptor_header *) &ss_iso_source_comp_desc,
        (struct usb_descriptor_header *) &ss_iso_sink_desc,
        (struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
-       (struct usb_descriptor_header *) &source_sink_intf_alt2,
-#define SS_ALT_IFC_2_OFFSET    14
-       (struct usb_descriptor_header *) &ss_int_source_desc,
-       (struct usb_descriptor_header *) &ss_int_source_comp_desc,
-       (struct usb_descriptor_header *) &ss_int_sink_desc,
-       (struct usb_descriptor_header *) &ss_int_sink_comp_desc,
        NULL,
 };
 
@@ -414,21 +301,6 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
 };
 
 /*-------------------------------------------------------------------------*/
-static const char *get_ep_string(enum eptype ep_type)
-{
-       switch (ep_type) {
-       case EP_ISOC:
-               return "ISOC-";
-       case EP_INTERRUPT:
-               return "INTERRUPT-";
-       case EP_CONTROL:
-               return "CTRL-";
-       case EP_BULK:
-               return "BULK-";
-       default:
-               return "UNKNOWN-";
-       }
-}
 
 static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
 {
@@ -456,8 +328,7 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
 
 void disable_endpoints(struct usb_composite_dev *cdev,
                struct usb_ep *in, struct usb_ep *out,
-               struct usb_ep *iso_in, struct usb_ep *iso_out,
-               struct usb_ep *int_in, struct usb_ep *int_out)
+               struct usb_ep *iso_in, struct usb_ep *iso_out)
 {
        disable_ep(cdev, in);
        disable_ep(cdev, out);
@@ -465,10 +336,6 @@ void disable_endpoints(struct usb_composite_dev *cdev,
                disable_ep(cdev, iso_in);
        if (iso_out)
                disable_ep(cdev, iso_out);
-       if (int_in)
-               disable_ep(cdev, int_in);
-       if (int_out)
-               disable_ep(cdev, int_out);
 }
 
 static int
@@ -485,7 +352,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
                return id;
        source_sink_intf_alt0.bInterfaceNumber = id;
        source_sink_intf_alt1.bInterfaceNumber = id;
-       source_sink_intf_alt2.bInterfaceNumber = id;
 
        /* allocate bulk endpoints */
        ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
@@ -546,55 +412,14 @@ no_iso:
        if (isoc_maxpacket > 1024)
                isoc_maxpacket = 1024;
 
-       /* sanity check the interrupt module parameters */
-       if (int_interval < 1)
-               int_interval = 1;
-       if (int_interval > 4096)
-               int_interval = 4096;
-       if (int_mult > 2)
-               int_mult = 2;
-       if (int_maxburst > 15)
-               int_maxburst = 15;
-
-       /* fill in the FS interrupt descriptors from the module parameters */
-       fs_int_source_desc.wMaxPacketSize = int_maxpacket > 64 ?
-                                               64 : int_maxpacket;
-       fs_int_source_desc.bInterval = int_interval > 255 ?
-                                               255 : int_interval;
-       fs_int_sink_desc.wMaxPacketSize = int_maxpacket > 64 ?
-                                               64 : int_maxpacket;
-       fs_int_sink_desc.bInterval = int_interval > 255 ?
-                                               255 : int_interval;
-
-       /* allocate int endpoints */
-       ss->int_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_source_desc);
-       if (!ss->int_in_ep)
-               goto no_int;
-       ss->int_in_ep->driver_data = cdev;      /* claim */
-
-       ss->int_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_int_sink_desc);
-       if (ss->int_out_ep) {
-               ss->int_out_ep->driver_data = cdev;     /* claim */
-       } else {
-               ss->int_in_ep->driver_data = NULL;
-               ss->int_in_ep = NULL;
-no_int:
-               fs_source_sink_descs[FS_ALT_IFC_2_OFFSET] = NULL;
-               hs_source_sink_descs[HS_ALT_IFC_2_OFFSET] = NULL;
-               ss_source_sink_descs[SS_ALT_IFC_2_OFFSET] = NULL;
-       }
-
-       if (int_maxpacket > 1024)
-               int_maxpacket = 1024;
-
        /* support high speed hardware */
        hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
        hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 
        /*
-        * Fill in the HS isoc and interrupt descriptors from the module
-        * parameters. We assume that the user knows what they are doing and
-        * won't give parameters that their UDC doesn't support.
+        * Fill in the HS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
         */
        hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
        hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
@@ -607,17 +432,6 @@ no_int:
        hs_iso_sink_desc.bInterval = isoc_interval;
        hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
-       hs_int_source_desc.wMaxPacketSize = int_maxpacket;
-       hs_int_source_desc.wMaxPacketSize |= int_mult << 11;
-       hs_int_source_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
-       hs_int_source_desc.bEndpointAddress =
-               fs_int_source_desc.bEndpointAddress;
-
-       hs_int_sink_desc.wMaxPacketSize = int_maxpacket;
-       hs_int_sink_desc.wMaxPacketSize |= int_mult << 11;
-       hs_int_sink_desc.bInterval = USB_MS_TO_HS_INTERVAL(int_interval);
-       hs_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
-
        /* support super speed hardware */
        ss_source_desc.bEndpointAddress =
                fs_source_desc.bEndpointAddress;
@@ -625,9 +439,9 @@ no_int:
                fs_sink_desc.bEndpointAddress;
 
        /*
-        * Fill in the SS isoc and interrupt descriptors from the module
-        * parameters. We assume that the user knows what they are doing and
-        * won't give parameters that their UDC doesn't support.
+        * Fill in the SS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
         */
        ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
        ss_iso_source_desc.bInterval = isoc_interval;
@@ -646,37 +460,17 @@ no_int:
                isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
        ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
-       ss_int_source_desc.wMaxPacketSize = int_maxpacket;
-       ss_int_source_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
-       ss_int_source_comp_desc.bmAttributes = int_mult;
-       ss_int_source_comp_desc.bMaxBurst = int_maxburst;
-       ss_int_source_comp_desc.wBytesPerInterval =
-               int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
-       ss_int_source_desc.bEndpointAddress =
-               fs_int_source_desc.bEndpointAddress;
-
-       ss_int_sink_desc.wMaxPacketSize = int_maxpacket;
-       ss_int_sink_desc.bInterval = USB_MS_TO_SS_INTERVAL(int_interval);
-       ss_int_sink_comp_desc.bmAttributes = int_mult;
-       ss_int_sink_comp_desc.bMaxBurst = int_maxburst;
-       ss_int_sink_comp_desc.wBytesPerInterval =
-               int_maxpacket * (int_mult + 1) * (int_maxburst + 1);
-       ss_int_sink_desc.bEndpointAddress = fs_int_sink_desc.bEndpointAddress;
-
        ret = usb_assign_descriptors(f, fs_source_sink_descs,
                        hs_source_sink_descs, ss_source_sink_descs);
        if (ret)
                return ret;
 
-       DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s, "
-                       "INT-IN/%s, INT-OUT/%s\n",
+       DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
             (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
                        f->name, ss->in_ep->name, ss->out_ep->name,
                        ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
-                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>",
-                       ss->int_in_ep ? ss->int_in_ep->name : "<none>",
-                       ss->int_out_ep ? ss->int_out_ep->name : "<none>");
+                       ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
        return 0;
 }
 
@@ -807,15 +601,14 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 }
 
 static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
-               enum eptype ep_type, int speed)
+               bool is_iso, int speed)
 {
        struct usb_ep           *ep;
        struct usb_request      *req;
        int                     i, size, status;
 
        for (i = 0; i < 8; i++) {
-               switch (ep_type) {
-               case EP_ISOC:
+               if (is_iso) {
                        switch (speed) {
                        case USB_SPEED_SUPER:
                                size = isoc_maxpacket * (isoc_mult + 1) *
@@ -831,28 +624,9 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
                        }
                        ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
                        req = ss_alloc_ep_req(ep, size);
-                       break;
-               case EP_INTERRUPT:
-                       switch (speed) {
-                       case USB_SPEED_SUPER:
-                               size = int_maxpacket * (int_mult + 1) *
-                                               (int_maxburst + 1);
-                               break;
-                       case USB_SPEED_HIGH:
-                               size = int_maxpacket * (int_mult + 1);
-                               break;
-                       default:
-                               size = int_maxpacket > 1023 ?
-                                               1023 : int_maxpacket;
-                               break;
-                       }
-                       ep = is_in ? ss->int_in_ep : ss->int_out_ep;
-                       req = ss_alloc_ep_req(ep, size);
-                       break;
-               default:
+               } else {
                        ep = is_in ? ss->in_ep : ss->out_ep;
                        req = ss_alloc_ep_req(ep, 0);
-                       break;
                }
 
                if (!req)
@@ -870,12 +644,12 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 
                        cdev = ss->function.config->cdev;
                        ERROR(cdev, "start %s%s %s --> %d\n",
-                               get_ep_string(ep_type), is_in ? "IN" : "OUT",
-                               ep->name, status);
+                             is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
+                             ep->name, status);
                        free_ep_req(ep, req);
                }
 
-               if (!(ep_type == EP_ISOC))
+               if (!is_iso)
                        break;
        }
 
@@ -888,7 +662,7 @@ static void disable_source_sink(struct f_sourcesink *ss)
 
        cdev = ss->function.config->cdev;
        disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
-                       ss->iso_out_ep, ss->int_in_ep, ss->int_out_ep);
+                       ss->iso_out_ep);
        VDBG(cdev, "%s disabled\n", ss->function.name);
 }
 
@@ -900,62 +674,6 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
        int                                     speed = cdev->gadget->speed;
        struct usb_ep                           *ep;
 
-       if (alt == 2) {
-               /* Configure for periodic interrupt endpoint */
-               ep = ss->int_in_ep;
-               if (ep) {
-                       result = config_ep_by_speed(cdev->gadget,
-                                       &(ss->function), ep);
-                       if (result)
-                               return result;
-
-                       result = usb_ep_enable(ep);
-                       if (result < 0)
-                               return result;
-
-                       ep->driver_data = ss;
-                       result = source_sink_start_ep(ss, true, EP_INTERRUPT,
-                                       speed);
-                       if (result < 0) {
-fail1:
-                               ep = ss->int_in_ep;
-                               if (ep) {
-                                       usb_ep_disable(ep);
-                                       ep->driver_data = NULL;
-                               }
-                               return result;
-                       }
-               }
-
-               /*
-                * one interrupt endpoint reads (sinks) anything OUT (from the
-                * host)
-                */
-               ep = ss->int_out_ep;
-               if (ep) {
-                       result = config_ep_by_speed(cdev->gadget,
-                                       &(ss->function), ep);
-                       if (result)
-                               goto fail1;
-
-                       result = usb_ep_enable(ep);
-                       if (result < 0)
-                               goto fail1;
-
-                       ep->driver_data = ss;
-                       result = source_sink_start_ep(ss, false, EP_INTERRUPT,
-                                       speed);
-                       if (result < 0) {
-                               ep = ss->int_out_ep;
-                               usb_ep_disable(ep);
-                               ep->driver_data = NULL;
-                               goto fail1;
-                       }
-               }
-
-               goto out;
-       }
-
        /* one bulk endpoint writes (sources) zeroes IN (to the host) */
        ep = ss->in_ep;
        result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
@@ -966,7 +684,7 @@ fail1:
                return result;
        ep->driver_data = ss;
 
-       result = source_sink_start_ep(ss, true, EP_BULK, speed);
+       result = source_sink_start_ep(ss, true, false, speed);
        if (result < 0) {
 fail:
                ep = ss->in_ep;
@@ -985,7 +703,7 @@ fail:
                goto fail;
        ep->driver_data = ss;
 
-       result = source_sink_start_ep(ss, false, EP_BULK, speed);
+       result = source_sink_start_ep(ss, false, false, speed);
        if (result < 0) {
 fail2:
                ep = ss->out_ep;
@@ -1008,7 +726,7 @@ fail2:
                        goto fail2;
                ep->driver_data = ss;
 
-               result = source_sink_start_ep(ss, true, EP_ISOC, speed);
+               result = source_sink_start_ep(ss, true, true, speed);
                if (result < 0) {
 fail3:
                        ep = ss->iso_in_ep;
@@ -1031,14 +749,13 @@ fail3:
                        goto fail3;
                ep->driver_data = ss;
 
-               result = source_sink_start_ep(ss, false, EP_ISOC, speed);
+               result = source_sink_start_ep(ss, false, true, speed);
                if (result < 0) {
                        usb_ep_disable(ep);
                        ep->driver_data = NULL;
                        goto fail3;
                }
        }
-
 out:
        ss->cur_alt = alt;
 
@@ -1054,8 +771,6 @@ static int sourcesink_set_alt(struct usb_function *f,
 
        if (ss->in_ep->driver_data)
                disable_source_sink(ss);
-       else if (alt == 2 && ss->int_in_ep->driver_data)
-               disable_source_sink(ss);
        return enable_source_sink(cdev, ss, alt);
 }
 
@@ -1168,10 +883,6 @@ static struct usb_function *source_sink_alloc_func(
        isoc_maxpacket = ss_opts->isoc_maxpacket;
        isoc_mult = ss_opts->isoc_mult;
        isoc_maxburst = ss_opts->isoc_maxburst;
-       int_interval = ss_opts->int_interval;
-       int_maxpacket = ss_opts->int_maxpacket;
-       int_mult = ss_opts->int_mult;
-       int_maxburst = ss_opts->int_maxburst;
        buflen = ss_opts->bulk_buflen;
 
        ss->function.name = "source/sink";
@@ -1468,182 +1179,6 @@ static struct f_ss_opts_attribute f_ss_opts_bulk_buflen =
                        f_ss_opts_bulk_buflen_show,
                        f_ss_opts_bulk_buflen_store);
 
-static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_interval);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_interval_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u32 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou32(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 4096) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_interval = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_interval =
-       __CONFIGFS_ATTR(int_interval, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_interval_show,
-                       f_ss_opts_int_interval_store);
-
-static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_maxpacket);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_maxpacket_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u16 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou16(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 1024) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_maxpacket = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_maxpacket =
-       __CONFIGFS_ATTR(int_maxpacket, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_maxpacket_show,
-                       f_ss_opts_int_maxpacket_store);
-
-static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_mult);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_mult_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u8 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou8(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 2) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_mult = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_mult =
-       __CONFIGFS_ATTR(int_mult, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_mult_show,
-                       f_ss_opts_int_mult_store);
-
-static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
-{
-       int result;
-
-       mutex_lock(&opts->lock);
-       result = sprintf(page, "%u", opts->int_maxburst);
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_ss_opts_int_maxburst_store(struct f_ss_opts *opts,
-                                      const char *page, size_t len)
-{
-       int ret;
-       u8 num;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       ret = kstrtou8(page, 0, &num);
-       if (ret)
-               goto end;
-
-       if (num > 15) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       opts->int_maxburst = num;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-static struct f_ss_opts_attribute f_ss_opts_int_maxburst =
-       __CONFIGFS_ATTR(int_maxburst, S_IRUGO | S_IWUSR,
-                       f_ss_opts_int_maxburst_show,
-                       f_ss_opts_int_maxburst_store);
-
 static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_pattern.attr,
        &f_ss_opts_isoc_interval.attr,
@@ -1651,10 +1186,6 @@ static struct configfs_attribute *ss_attrs[] = {
        &f_ss_opts_isoc_mult.attr,
        &f_ss_opts_isoc_maxburst.attr,
        &f_ss_opts_bulk_buflen.attr,
-       &f_ss_opts_int_interval.attr,
-       &f_ss_opts_int_maxpacket.attr,
-       &f_ss_opts_int_mult.attr,
-       &f_ss_opts_int_maxburst.attr,
        NULL,
 };
 
@@ -1684,8 +1215,6 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
        ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
        ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
        ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;
-       ss_opts->int_interval = GZERO_INT_INTERVAL;
-       ss_opts->int_maxpacket = GZERO_INT_MAXPACKET;
 
        config_group_init_type_name(&ss_opts->func_inst.group, "",
                                    &ss_func_type);
index 33e16658e5cfeb50d01c44c7a63a2379634e82b7..6d3eb8b00a488446db954334e80ac12eccf0d5cf 100644 (file)
@@ -54,7 +54,7 @@
 #define UNFLW_CTRL     8
 #define OVFLW_CTRL     10
 
-const char *uac2_name = "snd_uac2";
+static const char *uac2_name = "snd_uac2";
 
 struct uac2_req {
        struct uac2_rtd_params *pp; /* parent param */
@@ -634,7 +634,7 @@ static struct usb_interface_descriptor std_ac_if_desc = {
 };
 
 /* Clock source for IN traffic */
-struct uac_clock_source_descriptor in_clk_src_desc = {
+static struct uac_clock_source_descriptor in_clk_src_desc = {
        .bLength = sizeof in_clk_src_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -646,7 +646,7 @@ struct uac_clock_source_descriptor in_clk_src_desc = {
 };
 
 /* Clock source for OUT traffic */
-struct uac_clock_source_descriptor out_clk_src_desc = {
+static struct uac_clock_source_descriptor out_clk_src_desc = {
        .bLength = sizeof out_clk_src_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -658,7 +658,7 @@ struct uac_clock_source_descriptor out_clk_src_desc = {
 };
 
 /* Input Terminal for USB_OUT */
-struct uac2_input_terminal_descriptor usb_out_it_desc = {
+static struct uac2_input_terminal_descriptor usb_out_it_desc = {
        .bLength = sizeof usb_out_it_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -672,7 +672,7 @@ struct uac2_input_terminal_descriptor usb_out_it_desc = {
 };
 
 /* Input Terminal for I/O-In */
-struct uac2_input_terminal_descriptor io_in_it_desc = {
+static struct uac2_input_terminal_descriptor io_in_it_desc = {
        .bLength = sizeof io_in_it_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -686,7 +686,7 @@ struct uac2_input_terminal_descriptor io_in_it_desc = {
 };
 
 /* Ouput Terminal for USB_IN */
-struct uac2_output_terminal_descriptor usb_in_ot_desc = {
+static struct uac2_output_terminal_descriptor usb_in_ot_desc = {
        .bLength = sizeof usb_in_ot_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -700,7 +700,7 @@ struct uac2_output_terminal_descriptor usb_in_ot_desc = {
 };
 
 /* Ouput Terminal for I/O-Out */
-struct uac2_output_terminal_descriptor io_out_ot_desc = {
+static struct uac2_output_terminal_descriptor io_out_ot_desc = {
        .bLength = sizeof io_out_ot_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -713,7 +713,7 @@ struct uac2_output_terminal_descriptor io_out_ot_desc = {
        .bmControls = (CONTROL_RDWR << COPY_CTRL),
 };
 
-struct uac2_ac_header_descriptor ac_hdr_desc = {
+static struct uac2_ac_header_descriptor ac_hdr_desc = {
        .bLength = sizeof ac_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -751,7 +751,7 @@ static struct usb_interface_descriptor std_as_out_if1_desc = {
 };
 
 /* Audio Stream OUT Intface Desc */
-struct uac2_as_header_descriptor as_out_hdr_desc = {
+static struct uac2_as_header_descriptor as_out_hdr_desc = {
        .bLength = sizeof as_out_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -764,7 +764,7 @@ struct uac2_as_header_descriptor as_out_hdr_desc = {
 };
 
 /* Audio USB_OUT Format */
-struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
+static struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
        .bLength = sizeof as_out_fmt1_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype = UAC_FORMAT_TYPE,
@@ -772,7 +772,7 @@ struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
 };
 
 /* STD AS ISO OUT Endpoint */
-struct usb_endpoint_descriptor fs_epout_desc = {
+static struct usb_endpoint_descriptor fs_epout_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -782,7 +782,7 @@ struct usb_endpoint_descriptor fs_epout_desc = {
        .bInterval = 1,
 };
 
-struct usb_endpoint_descriptor hs_epout_desc = {
+static struct usb_endpoint_descriptor hs_epout_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -828,7 +828,7 @@ static struct usb_interface_descriptor std_as_in_if1_desc = {
 };
 
 /* Audio Stream IN Intface Desc */
-struct uac2_as_header_descriptor as_in_hdr_desc = {
+static struct uac2_as_header_descriptor as_in_hdr_desc = {
        .bLength = sizeof as_in_hdr_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
 
@@ -841,7 +841,7 @@ struct uac2_as_header_descriptor as_in_hdr_desc = {
 };
 
 /* Audio USB_IN Format */
-struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
+static struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
        .bLength = sizeof as_in_fmt1_desc,
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubtype = UAC_FORMAT_TYPE,
@@ -849,7 +849,7 @@ struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
 };
 
 /* STD AS ISO IN Endpoint */
-struct usb_endpoint_descriptor fs_epin_desc = {
+static struct usb_endpoint_descriptor fs_epin_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -859,7 +859,7 @@ struct usb_endpoint_descriptor fs_epin_desc = {
        .bInterval = 1,
 };
 
-struct usb_endpoint_descriptor hs_epin_desc = {
+static struct usb_endpoint_descriptor hs_epin_desc = {
        .bLength = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
@@ -1563,7 +1563,7 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
                agdev->out_ep->driver_data = NULL;
 }
 
-struct usb_function *afunc_alloc(struct usb_function_instance *fi)
+static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
 {
        struct audio_dev *agdev;
        struct f_uac2_opts *opts;
index 2ce28b9d97cc81a519cff3adb6e07fa89aeb9e2a..15f180904f8a3980e2845c38bf327e5174b8df30 100644 (file)
@@ -10,8 +10,6 @@
 #define GZERO_QLEN             32
 #define GZERO_ISOC_INTERVAL    4
 #define GZERO_ISOC_MAXPACKET   1024
-#define GZERO_INT_INTERVAL     1 /* Default interrupt interval = 1 ms */
-#define GZERO_INT_MAXPACKET    1024
 
 struct usb_zero_options {
        unsigned pattern;
@@ -19,10 +17,6 @@ struct usb_zero_options {
        unsigned isoc_maxpacket;
        unsigned isoc_mult;
        unsigned isoc_maxburst;
-       unsigned int_interval; /* In ms */
-       unsigned int_maxpacket;
-       unsigned int_mult;
-       unsigned int_maxburst;
        unsigned bulk_buflen;
        unsigned qlen;
 };
@@ -34,10 +28,6 @@ struct f_ss_opts {
        unsigned isoc_maxpacket;
        unsigned isoc_mult;
        unsigned isoc_maxburst;
-       unsigned int_interval; /* In ms */
-       unsigned int_maxpacket;
-       unsigned int_mult;
-       unsigned int_maxburst;
        unsigned bulk_buflen;
 
        /*
@@ -72,7 +62,6 @@ int lb_modinit(void);
 void free_ep_req(struct usb_ep *ep, struct usb_request *req);
 void disable_endpoints(struct usb_composite_dev *cdev,
                struct usb_ep *in, struct usb_ep *out,
-               struct usb_ep *iso_in, struct usb_ep *iso_out,
-               struct usb_ep *int_in, struct usb_ep *int_out);
+               struct usb_ep *iso_in, struct usb_ep *iso_out);
 
 #endif /* __G_ZERO_H */
index 5aad7fededa589bdb7b143a9f6dfbfb65c81cedd..8b818fd027b3380772030c2a650c67df830a4e56 100644 (file)
@@ -27,6 +27,7 @@
 #include "uvc.h"
 #include "uvc_queue.h"
 #include "uvc_video.h"
+#include "uvc_v4l2.h"
 
 /* --------------------------------------------------------------------------
  * Requests handling
index 9cb86bc1a9a5444b4ed7895489c2b0c5860bac37..50a5e637ca35ad804925112675e54b2ee115b80f 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "uvc.h"
 #include "uvc_queue.h"
+#include "uvc_video.h"
 
 /* --------------------------------------------------------------------------
  * Video codecs
index 06acfa55864a639a6015689770b4ccb06f01ad40..b01b88e1b716a5902d5276196ef459663545a216 100644 (file)
@@ -133,7 +133,9 @@ struct gfs_configuration {
        struct usb_configuration c;
        int (*eth)(struct usb_configuration *c);
        int num;
-} gfs_configurations[] = {
+};
+
+static struct gfs_configuration gfs_configurations[] = {
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        {
                .eth            = bind_rndis_config,
@@ -278,7 +280,7 @@ static void *functionfs_acquire_dev(struct ffs_dev *dev)
        if (!try_module_get(THIS_MODULE))
                return ERR_PTR(-ENOENT);
        
-       return 0;
+       return NULL;
 }
 
 static void functionfs_release_dev(struct ffs_dev *dev)
index db49ec4c748e9469bd694645c8cfc22df7c829fa..200f9a584064fd9199ba99ff75a2e26a33c788f7 100644 (file)
@@ -74,6 +74,8 @@ MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");
 MODULE_LICENSE ("GPL");
 
+static int ep_open(struct inode *, struct file *);
+
 
 /*----------------------------------------------------------------------*/
 
@@ -283,14 +285,15 @@ static void epio_complete (struct usb_ep *ep, struct usb_request *req)
  * still need dev->lock to use epdata->ep.
  */
 static int
-get_ready_ep (unsigned f_flags, struct ep_data *epdata)
+get_ready_ep (unsigned f_flags, struct ep_data *epdata, bool is_write)
 {
        int     val;
 
        if (f_flags & O_NONBLOCK) {
                if (!mutex_trylock(&epdata->lock))
                        goto nonblock;
-               if (epdata->state != STATE_EP_ENABLED) {
+               if (epdata->state != STATE_EP_ENABLED &&
+                   (!is_write || epdata->state != STATE_EP_READY)) {
                        mutex_unlock(&epdata->lock);
 nonblock:
                        val = -EAGAIN;
@@ -305,18 +308,20 @@ nonblock:
 
        switch (epdata->state) {
        case STATE_EP_ENABLED:
+               return 0;
+       case STATE_EP_READY:                    /* not configured yet */
+               if (is_write)
+                       return 0;
+               // FALLTHRU
+       case STATE_EP_UNBOUND:                  /* clean disconnect */
                break;
        // case STATE_EP_DISABLED:              /* "can't happen" */
-       // case STATE_EP_READY:                 /* "can't happen" */
        default:                                /* error! */
                pr_debug ("%s: ep %p not available, state %d\n",
                                shortname, epdata, epdata->state);
-               // FALLTHROUGH
-       case STATE_EP_UNBOUND:                  /* clean disconnect */
-               val = -ENODEV;
-               mutex_unlock(&epdata->lock);
        }
-       return val;
+       mutex_unlock(&epdata->lock);
+       return -ENODEV;
 }
 
 static ssize_t
@@ -363,97 +368,6 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len)
        return value;
 }
 
-
-/* handle a synchronous OUT bulk/intr/iso transfer */
-static ssize_t
-ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       void                    *kbuf;
-       ssize_t                 value;
-
-       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
-               return value;
-
-       /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc)) {
-                       mutex_unlock(&data->lock);
-                       return -EINVAL;
-               }
-               DBG (data->dev, "%s halt\n", data->name);
-               spin_lock_irq (&data->dev->lock);
-               if (likely (data->ep != NULL))
-                       usb_ep_set_halt (data->ep);
-               spin_unlock_irq (&data->dev->lock);
-               mutex_unlock(&data->lock);
-               return -EBADMSG;
-       }
-
-       /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */
-
-       value = -ENOMEM;
-       kbuf = kmalloc (len, GFP_KERNEL);
-       if (unlikely (!kbuf))
-               goto free1;
-
-       value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
-               data->name, len, (int) value);
-       if (value >= 0 && copy_to_user (buf, kbuf, value))
-               value = -EFAULT;
-
-free1:
-       mutex_unlock(&data->lock);
-       kfree (kbuf);
-       return value;
-}
-
-/* handle a synchronous IN bulk/intr/iso transfer */
-static ssize_t
-ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       void                    *kbuf;
-       ssize_t                 value;
-
-       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
-               return value;
-
-       /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (!usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc)) {
-                       mutex_unlock(&data->lock);
-                       return -EINVAL;
-               }
-               DBG (data->dev, "%s halt\n", data->name);
-               spin_lock_irq (&data->dev->lock);
-               if (likely (data->ep != NULL))
-                       usb_ep_set_halt (data->ep);
-               spin_unlock_irq (&data->dev->lock);
-               mutex_unlock(&data->lock);
-               return -EBADMSG;
-       }
-
-       /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
-
-       value = -ENOMEM;
-       kbuf = memdup_user(buf, len);
-       if (IS_ERR(kbuf)) {
-               value = PTR_ERR(kbuf);
-               kbuf = NULL;
-               goto free1;
-       }
-
-       value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s write %zu IN, status %d\n",
-               data->name, len, (int) value);
-free1:
-       mutex_unlock(&data->lock);
-       kfree (kbuf);
-       return value;
-}
-
 static int
 ep_release (struct inode *inode, struct file *fd)
 {
@@ -481,7 +395,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
        struct ep_data          *data = fd->private_data;
        int                     status;
 
-       if ((status = get_ready_ep (fd->f_flags, data)) < 0)
+       if ((status = get_ready_ep (fd->f_flags, data, false)) < 0)
                return status;
 
        spin_lock_irq (&data->dev->lock);
@@ -517,8 +431,8 @@ struct kiocb_priv {
        struct mm_struct        *mm;
        struct work_struct      work;
        void                    *buf;
-       const struct iovec      *iv;
-       unsigned long           nr_segs;
+       struct iov_iter         to;
+       const void              *to_free;
        unsigned                actual;
 };
 
@@ -541,35 +455,6 @@ static int ep_aio_cancel(struct kiocb *iocb)
        return value;
 }
 
-static ssize_t ep_copy_to_user(struct kiocb_priv *priv)
-{
-       ssize_t                 len, total;
-       void                    *to_copy;
-       int                     i;
-
-       /* copy stuff into user buffers */
-       total = priv->actual;
-       len = 0;
-       to_copy = priv->buf;
-       for (i=0; i < priv->nr_segs; i++) {
-               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
-               if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
-                       if (len == 0)
-                               len = -EFAULT;
-                       break;
-               }
-
-               total -= this;
-               len += this;
-               to_copy += this;
-               if (total == 0)
-                       break;
-       }
-
-       return len;
-}
-
 static void ep_user_copy_worker(struct work_struct *work)
 {
        struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work);
@@ -578,13 +463,16 @@ static void ep_user_copy_worker(struct work_struct *work)
        size_t ret;
 
        use_mm(mm);
-       ret = ep_copy_to_user(priv);
+       ret = copy_to_iter(priv->buf, priv->actual, &priv->to);
        unuse_mm(mm);
+       if (!ret)
+               ret = -EFAULT;
 
        /* completing the iocb can drop the ctx and mm, don't touch mm after */
        aio_complete(iocb, ret, ret);
 
        kfree(priv->buf);
+       kfree(priv->to_free);
        kfree(priv);
 }
 
@@ -603,8 +491,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
         * don't need to copy anything to userspace, so we can
         * complete the aio request immediately.
         */
-       if (priv->iv == NULL || unlikely(req->actual == 0)) {
+       if (priv->to_free == NULL || unlikely(req->actual == 0)) {
                kfree(req->buf);
+               kfree(priv->to_free);
                kfree(priv);
                iocb->private = NULL;
                /* aio_complete() reports bytes-transferred _and_ faults */
@@ -618,6 +507,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
 
                priv->buf = req->buf;
                priv->actual = req->actual;
+               INIT_WORK(&priv->work, ep_user_copy_worker);
                schedule_work(&priv->work);
        }
        spin_unlock(&epdata->dev->lock);
@@ -626,38 +516,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
        put_ep(epdata);
 }
 
-static ssize_t
-ep_aio_rwtail(
-       struct kiocb    *iocb,
-       char            *buf,
-       size_t          len,
-       struct ep_data  *epdata,
-       const struct iovec *iv,
-       unsigned long   nr_segs
-)
+static ssize_t ep_aio(struct kiocb *iocb,
+                     struct kiocb_priv *priv,
+                     struct ep_data *epdata,
+                     char *buf,
+                     size_t len)
 {
-       struct kiocb_priv       *priv;
-       struct usb_request      *req;
-       ssize_t                 value;
+       struct usb_request *req;
+       ssize_t value;
 
-       priv = kmalloc(sizeof *priv, GFP_KERNEL);
-       if (!priv) {
-               value = -ENOMEM;
-fail:
-               kfree(buf);
-               return value;
-       }
        iocb->private = priv;
        priv->iocb = iocb;
-       priv->iv = iv;
-       priv->nr_segs = nr_segs;
-       INIT_WORK(&priv->work, ep_user_copy_worker);
-
-       value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
-       if (unlikely(value < 0)) {
-               kfree(priv);
-               goto fail;
-       }
 
        kiocb_set_cancel_fn(iocb, ep_aio_cancel);
        get_ep(epdata);
@@ -669,75 +538,154 @@ fail:
         * allocate or submit those if the host disconnected.
         */
        spin_lock_irq(&epdata->dev->lock);
-       if (likely(epdata->ep)) {
-               req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
-               if (likely(req)) {
-                       priv->req = req;
-                       req->buf = buf;
-                       req->length = len;
-                       req->complete = ep_aio_complete;
-                       req->context = iocb;
-                       value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
-                       if (unlikely(0 != value))
-                               usb_ep_free_request(epdata->ep, req);
-               } else
-                       value = -EAGAIN;
-       } else
-               value = -ENODEV;
-       spin_unlock_irq(&epdata->dev->lock);
+       value = -ENODEV;
+       if (unlikely(epdata->ep))
+               goto fail;
 
-       mutex_unlock(&epdata->lock);
+       req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
+       value = -ENOMEM;
+       if (unlikely(!req))
+               goto fail;
 
-       if (unlikely(value)) {
-               kfree(priv);
-               put_ep(epdata);
-       } else
-               value = -EIOCBQUEUED;
+       priv->req = req;
+       req->buf = buf;
+       req->length = len;
+       req->complete = ep_aio_complete;
+       req->context = iocb;
+       value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
+       if (unlikely(0 != value)) {
+               usb_ep_free_request(epdata->ep, req);
+               goto fail;
+       }
+       spin_unlock_irq(&epdata->dev->lock);
+       return -EIOCBQUEUED;
+
+fail:
+       spin_unlock_irq(&epdata->dev->lock);
+       kfree(priv->to_free);
+       kfree(priv);
+       put_ep(epdata);
        return value;
 }
 
 static ssize_t
-ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t o)
+ep_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
-       struct ep_data          *epdata = iocb->ki_filp->private_data;
-       char                    *buf;
+       struct file *file = iocb->ki_filp;
+       struct ep_data *epdata = file->private_data;
+       size_t len = iov_iter_count(to);
+       ssize_t value;
+       char *buf;
 
-       if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
-               return -EINVAL;
+       if ((value = get_ready_ep(file->f_flags, epdata, false)) < 0)
+               return value;
 
-       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
-       if (unlikely(!buf))
-               return -ENOMEM;
+       /* halt any endpoint by doing a "wrong direction" i/o call */
+       if (usb_endpoint_dir_in(&epdata->desc)) {
+               if (usb_endpoint_xfer_isoc(&epdata->desc) ||
+                   !is_sync_kiocb(iocb)) {
+                       mutex_unlock(&epdata->lock);
+                       return -EINVAL;
+               }
+               DBG (epdata->dev, "%s halt\n", epdata->name);
+               spin_lock_irq(&epdata->dev->lock);
+               if (likely(epdata->ep != NULL))
+                       usb_ep_set_halt(epdata->ep);
+               spin_unlock_irq(&epdata->dev->lock);
+               mutex_unlock(&epdata->lock);
+               return -EBADMSG;
+       }
 
-       return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs);
+       buf = kmalloc(len, GFP_KERNEL);
+       if (unlikely(!buf)) {
+               mutex_unlock(&epdata->lock);
+               return -ENOMEM;
+       }
+       if (is_sync_kiocb(iocb)) {
+               value = ep_io(epdata, buf, len);
+               if (value >= 0 && copy_to_iter(buf, value, to))
+                       value = -EFAULT;
+       } else {
+               struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL);
+               value = -ENOMEM;
+               if (!priv)
+                       goto fail;
+               priv->to_free = dup_iter(&priv->to, to, GFP_KERNEL);
+               if (!priv->to_free) {
+                       kfree(priv);
+                       goto fail;
+               }
+               value = ep_aio(iocb, priv, epdata, buf, len);
+               if (value == -EIOCBQUEUED)
+                       buf = NULL;
+       }
+fail:
+       kfree(buf);
+       mutex_unlock(&epdata->lock);
+       return value;
 }
 
+static ssize_t ep_config(struct ep_data *, const char *, size_t);
+
 static ssize_t
-ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t o)
+ep_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
-       struct ep_data          *epdata = iocb->ki_filp->private_data;
-       char                    *buf;
-       size_t                  len = 0;
-       int                     i = 0;
+       struct file *file = iocb->ki_filp;
+       struct ep_data *epdata = file->private_data;
+       size_t len = iov_iter_count(from);
+       bool configured;
+       ssize_t value;
+       char *buf;
+
+       if ((value = get_ready_ep(file->f_flags, epdata, true)) < 0)
+               return value;
 
-       if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
-               return -EINVAL;
+       configured = epdata->state == STATE_EP_ENABLED;
 
-       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
-       if (unlikely(!buf))
+       /* halt any endpoint by doing a "wrong direction" i/o call */
+       if (configured && !usb_endpoint_dir_in(&epdata->desc)) {
+               if (usb_endpoint_xfer_isoc(&epdata->desc) ||
+                   !is_sync_kiocb(iocb)) {
+                       mutex_unlock(&epdata->lock);
+                       return -EINVAL;
+               }
+               DBG (epdata->dev, "%s halt\n", epdata->name);
+               spin_lock_irq(&epdata->dev->lock);
+               if (likely(epdata->ep != NULL))
+                       usb_ep_set_halt(epdata->ep);
+               spin_unlock_irq(&epdata->dev->lock);
+               mutex_unlock(&epdata->lock);
+               return -EBADMSG;
+       }
+
+       buf = kmalloc(len, GFP_KERNEL);
+       if (unlikely(!buf)) {
+               mutex_unlock(&epdata->lock);
                return -ENOMEM;
+       }
 
-       for (i=0; i < nr_segs; i++) {
-               if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
-                               iov[i].iov_len) != 0)) {
-                       kfree(buf);
-                       return -EFAULT;
+       if (unlikely(copy_from_iter(buf, len, from) != len)) {
+               value = -EFAULT;
+               goto out;
+       }
+
+       if (unlikely(!configured)) {
+               value = ep_config(epdata, buf, len);
+       } else if (is_sync_kiocb(iocb)) {
+               value = ep_io(epdata, buf, len);
+       } else {
+               struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL);
+               value = -ENOMEM;
+               if (priv) {
+                       value = ep_aio(iocb, priv, epdata, buf, len);
+                       if (value == -EIOCBQUEUED)
+                               buf = NULL;
                }
-               len += iov[i].iov_len;
        }
-       return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
+out:
+       kfree(buf);
+       mutex_unlock(&epdata->lock);
+       return value;
 }
 
 /*----------------------------------------------------------------------*/
@@ -745,15 +693,15 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
 /* used after endpoint configuration */
 static const struct file_operations ep_io_operations = {
        .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
 
-       .read =         ep_read,
-       .write =        ep_write,
-       .unlocked_ioctl = ep_ioctl,
+       .open =         ep_open,
        .release =      ep_release,
-
-       .aio_read =     ep_aio_read,
-       .aio_write =    ep_aio_write,
+       .llseek =       no_llseek,
+       .read =         new_sync_read,
+       .write =        new_sync_write,
+       .unlocked_ioctl = ep_ioctl,
+       .read_iter =    ep_read_iter,
+       .write_iter =   ep_write_iter,
 };
 
 /* ENDPOINT INITIALIZATION
@@ -770,17 +718,12 @@ static const struct file_operations ep_io_operations = {
  * speed descriptor, then optional high speed descriptor.
  */
 static ssize_t
-ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+ep_config (struct ep_data *data, const char *buf, size_t len)
 {
-       struct ep_data          *data = fd->private_data;
        struct usb_ep           *ep;
        u32                     tag;
        int                     value, length = len;
 
-       value = mutex_lock_interruptible(&data->lock);
-       if (value < 0)
-               return value;
-
        if (data->state != STATE_EP_READY) {
                value = -EL2HLT;
                goto fail;
@@ -791,9 +734,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                goto fail0;
 
        /* we might need to change message format someday */
-       if (copy_from_user (&tag, buf, 4)) {
-               goto fail1;
-       }
+       memcpy(&tag, buf, 4);
        if (tag != 1) {
                DBG(data->dev, "config %s, bad tag %d\n", data->name, tag);
                goto fail0;
@@ -806,19 +747,15 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
         */
 
        /* full/low speed descriptor, then high speed */
-       if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) {
-               goto fail1;
-       }
+       memcpy(&data->desc, buf, USB_DT_ENDPOINT_SIZE);
        if (data->desc.bLength != USB_DT_ENDPOINT_SIZE
                        || data->desc.bDescriptorType != USB_DT_ENDPOINT)
                goto fail0;
        if (len != USB_DT_ENDPOINT_SIZE) {
                if (len != 2 * USB_DT_ENDPOINT_SIZE)
                        goto fail0;
-               if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
-                                       USB_DT_ENDPOINT_SIZE)) {
-                       goto fail1;
-               }
+               memcpy(&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
+                       USB_DT_ENDPOINT_SIZE);
                if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE
                                || data->hs_desc.bDescriptorType
                                        != USB_DT_ENDPOINT) {
@@ -840,24 +777,20 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        case USB_SPEED_LOW:
        case USB_SPEED_FULL:
                ep->desc = &data->desc;
-               value = usb_ep_enable(ep);
-               if (value == 0)
-                       data->state = STATE_EP_ENABLED;
                break;
        case USB_SPEED_HIGH:
                /* fails if caller didn't provide that descriptor... */
                ep->desc = &data->hs_desc;
-               value = usb_ep_enable(ep);
-               if (value == 0)
-                       data->state = STATE_EP_ENABLED;
                break;
        default:
                DBG(data->dev, "unconnected, %s init abandoned\n",
                                data->name);
                value = -EINVAL;
+               goto gone;
        }
+       value = usb_ep_enable(ep);
        if (value == 0) {
-               fd->f_op = &ep_io_operations;
+               data->state = STATE_EP_ENABLED;
                value = length;
        }
 gone:
@@ -867,14 +800,10 @@ fail:
                data->desc.bDescriptorType = 0;
                data->hs_desc.bDescriptorType = 0;
        }
-       mutex_unlock(&data->lock);
        return value;
 fail0:
        value = -EINVAL;
        goto fail;
-fail1:
-       value = -EFAULT;
-       goto fail;
 }
 
 static int
@@ -902,15 +831,6 @@ ep_open (struct inode *inode, struct file *fd)
        return value;
 }
 
-/* used before endpoint configuration */
-static const struct file_operations ep_config_operations = {
-       .llseek =       no_llseek,
-
-       .open =         ep_open,
-       .write =        ep_config,
-       .release =      ep_release,
-};
-
 /*----------------------------------------------------------------------*/
 
 /* EP0 IMPLEMENTATION can be partly in userspace.
@@ -989,6 +909,10 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
        enum ep0_state                  state;
 
        spin_lock_irq (&dev->lock);
+       if (dev->state <= STATE_DEV_OPENED) {
+               retval = -EINVAL;
+               goto done;
+       }
 
        /* report fd mode change before acting on it */
        if (dev->setup_abort) {
@@ -1187,8 +1111,6 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        struct dev_data         *dev = fd->private_data;
        ssize_t                 retval = -ESRCH;
 
-       spin_lock_irq (&dev->lock);
-
        /* report fd mode change before acting on it */
        if (dev->setup_abort) {
                dev->setup_abort = 0;
@@ -1234,7 +1156,6 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        } else
                DBG (dev, "fail %s, state %d\n", __func__, dev->state);
 
-       spin_unlock_irq (&dev->lock);
        return retval;
 }
 
@@ -1281,6 +1202,9 @@ ep0_poll (struct file *fd, poll_table *wait)
        struct dev_data         *dev = fd->private_data;
        int                     mask = 0;
 
+       if (dev->state <= STATE_DEV_OPENED)
+               return DEFAULT_POLLMASK;
+
        poll_wait(fd, &dev->wait, wait);
 
        spin_lock_irq (&dev->lock);
@@ -1316,19 +1240,6 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
        return ret;
 }
 
-/* used after device configuration */
-static const struct file_operations ep0_io_operations = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-
-       .read =         ep0_read,
-       .write =        ep0_write,
-       .fasync =       ep0_fasync,
-       .poll =         ep0_poll,
-       .unlocked_ioctl =       dev_ioctl,
-       .release =      dev_release,
-};
-
 /*----------------------------------------------------------------------*/
 
 /* The in-kernel gadget driver handles most ep0 issues, in particular
@@ -1650,7 +1561,7 @@ static int activate_ep_files (struct dev_data *dev)
                        goto enomem1;
 
                data->dentry = gadgetfs_create_file (dev->sb, data->name,
-                               data, &ep_config_operations);
+                               data, &ep_io_operations);
                if (!data->dentry)
                        goto enomem2;
                list_add_tail (&data->epfiles, &dev->epfiles);
@@ -1852,6 +1763,14 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        u32                     tag;
        char                    *kbuf;
 
+       spin_lock_irq(&dev->lock);
+       if (dev->state > STATE_DEV_OPENED) {
+               value = ep0_write(fd, buf, len, ptr);
+               spin_unlock_irq(&dev->lock);
+               return value;
+       }
+       spin_unlock_irq(&dev->lock);
+
        if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
                return -EINVAL;
 
@@ -1925,7 +1844,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                 * on, they can work ... except in cleanup paths that
                 * kick in after the ep0 descriptor is closed.
                 */
-               fd->f_op = &ep0_io_operations;
                value = len;
        }
        return value;
@@ -1956,12 +1874,14 @@ dev_open (struct inode *inode, struct file *fd)
        return value;
 }
 
-static const struct file_operations dev_init_operations = {
+static const struct file_operations ep0_operations = {
        .llseek =       no_llseek,
 
        .open =         dev_open,
+       .read =         ep0_read,
        .write =        dev_config,
        .fasync =       ep0_fasync,
+       .poll =         ep0_poll,
        .unlocked_ioctl = dev_ioctl,
        .release =      dev_release,
 };
@@ -2077,7 +1997,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
                goto Enomem;
 
        dev->sb = sb;
-       dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &dev_init_operations);
+       dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations);
        if (!dev->dentry) {
                put_dev(dev);
                goto Enomem;
index 3a494168661e40c9f20e812bc1473620711aebb5..6e0a019aad54ae7a209f03355ae50d7c1e0cdb29 100644 (file)
@@ -1740,10 +1740,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
                goto err_session;
        }
        /*
-        * Now register the TCM vHost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vHost virtual I_T Nexus as active.
         */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
        mutex_unlock(&tpg->tpg_mutex);
index ff97ac93ac03d0add447f3e3ed49301403386b53..5ee95152493c2b6b0be74257cc437bdb560f250b 100644 (file)
@@ -68,8 +68,6 @@ static struct usb_zero_options gzero_options = {
        .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
        .bulk_buflen = GZERO_BULK_BUFLEN,
        .qlen = GZERO_QLEN,
-       .int_interval = GZERO_INT_INTERVAL,
-       .int_maxpacket = GZERO_INT_MAXPACKET,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -268,21 +266,6 @@ module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
                S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
 
-module_param_named(int_interval, gzero_options.int_interval, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_interval, "1 - 16");
-
-module_param_named(int_maxpacket, gzero_options.int_maxpacket, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
-
-module_param_named(int_mult, gzero_options.int_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_mult, "0 - 2 (hs/ss only)");
-
-module_param_named(int_maxburst, gzero_options.int_maxburst, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(int_maxburst, "0 - 15 (ss only)");
-
 static struct usb_function *func_lb;
 static struct usb_function_instance *func_inst_lb;
 
@@ -318,10 +301,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
        ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
        ss_opts->isoc_mult = gzero_options.isoc_mult;
        ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
-       ss_opts->int_interval = gzero_options.int_interval;
-       ss_opts->int_maxpacket = gzero_options.int_maxpacket;
-       ss_opts->int_mult = gzero_options.int_mult;
-       ss_opts->int_maxburst = gzero_options.int_maxburst;
        ss_opts->bulk_buflen = gzero_options.bulk_buflen;
 
        func_ss = usb_get_function(func_inst_ss);
index 663f7908b15c482c9f57bc921d3c976acb04bc53..be0964a801e819fd5dbf88bcee3c1f12f14fd039 100644 (file)
@@ -34,7 +34,6 @@ static const char hcd_name[] = "ehci-atmel";
 
 struct atmel_ehci_priv {
        struct clk *iclk;
-       struct clk *fclk;
        struct clk *uclk;
        bool clocked;
 };
@@ -51,12 +50,9 @@ static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
        if (atmel_ehci->clocked)
                return;
-       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-               clk_set_rate(atmel_ehci->uclk, 48000000);
-               clk_prepare_enable(atmel_ehci->uclk);
-       }
+
+       clk_prepare_enable(atmel_ehci->uclk);
        clk_prepare_enable(atmel_ehci->iclk);
-       clk_prepare_enable(atmel_ehci->fclk);
        atmel_ehci->clocked = true;
 }
 
@@ -64,10 +60,9 @@ static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
        if (!atmel_ehci->clocked)
                return;
-       clk_disable_unprepare(atmel_ehci->fclk);
+
        clk_disable_unprepare(atmel_ehci->iclk);
-       if (IS_ENABLED(CONFIG_COMMON_CLK))
-               clk_disable_unprepare(atmel_ehci->uclk);
+       clk_disable_unprepare(atmel_ehci->uclk);
        atmel_ehci->clocked = false;
 }
 
@@ -146,20 +141,13 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
                retval = -ENOENT;
                goto fail_request_resource;
        }
-       atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
-       if (IS_ERR(atmel_ehci->fclk)) {
-               dev_err(&pdev->dev, "Error getting function clock\n");
-               retval = -ENOENT;
+
+       atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
+       if (IS_ERR(atmel_ehci->uclk)) {
+               dev_err(&pdev->dev, "failed to get uclk\n");
+               retval = PTR_ERR(atmel_ehci->uclk);
                goto fail_request_resource;
        }
-       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-               atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
-               if (IS_ERR(atmel_ehci->uclk)) {
-                       dev_err(&pdev->dev, "failed to get uclk\n");
-                       retval = PTR_ERR(atmel_ehci->uclk);
-                       goto fail_request_resource;
-               }
-       }
 
        ehci = hcd_to_ehci(hcd);
        /* registers start at offset 0x0 */
index a7865c4b04980898b49317386ad6138aab051bc5..0827d7c965276382418f0a602ec5c1412c023142 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 7f76c8a12f89db425e19c4f3a2a5200de542dbd7..2af32e26fafc3727279fe656fbbcaf158736371d 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 08d402b15482d936ca36d6d20cc381d8279a35a2..0e11d61408ff3f95a3110636e858119f4037cf0c 100644 (file)
@@ -83,16 +83,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
        if (irq < 0)
                return -ENODEV;
 
-
-       if (of_device_is_compatible(pdev->dev.of_node,
-                                   "marvell,armada-375-xhci") ||
-           of_device_is_compatible(pdev->dev.of_node,
-                                   "marvell,armada-380-xhci")) {
-               ret = xhci_mvebu_mbus_init_quirk(pdev);
-               if (ret)
-                       return ret;
-       }
-
        /* Initialize dma_mask and coherent_dma_mask to 32-bits */
        ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
        if (ret)
@@ -127,6 +117,15 @@ static int xhci_plat_probe(struct platform_device *pdev)
                        goto put_hcd;
        }
 
+       if (of_device_is_compatible(pdev->dev.of_node,
+                                   "marvell,armada-375-xhci") ||
+           of_device_is_compatible(pdev->dev.of_node,
+                                   "marvell,armada-380-xhci")) {
+               ret = xhci_mvebu_mbus_init_quirk(pdev);
+               if (ret)
+                       goto disable_clk;
+       }
+
        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret)
                goto disable_clk;
index 88da8d6298201fa5c7b7e4a93ff67fe303cb84b5..73485fa4372ff7d89298d4d8968fd28d5ec43265 100644 (file)
@@ -1946,7 +1946,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
        if (event_trb != ep_ring->dequeue) {
                /* The event was for the status stage */
                if (event_trb == td->last_trb) {
-                       if (td->urb->actual_length != 0) {
+                       if (td->urb_length_set) {
                                /* Don't overwrite a previously set error code
                                 */
                                if ((*status == -EINPROGRESS || *status == 0) &&
@@ -1960,7 +1960,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                                        td->urb->transfer_buffer_length;
                        }
                } else {
-               /* Maybe the event was for the data stage? */
+                       /*
+                        * Maybe the event was for the data stage? If so, update
+                        * already the actual_length of the URB and flag it as
+                        * set, so that it is not overwritten in the event for
+                        * the last TRB.
+                        */
+                       td->urb_length_set = true;
                        td->urb->actual_length =
                                td->urb->transfer_buffer_length -
                                EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
index 974514762a1402aee4164cf5556c9321bea49d44..8e421b89632ddaa4eaf30ee34ef60f89b7ac3e2d 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * xHCI host controller driver
  *
@@ -88,9 +89,10 @@ struct xhci_cap_regs {
 #define HCS_IST(p)             (((p) >> 0) & 0xf)
 /* bits 4:7, max number of Event Ring segments */
 #define HCS_ERST_MAX(p)                (((p) >> 4) & 0xf)
+/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */
 /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
-/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */
-#define HCS_MAX_SCRATCHPAD(p)   (((p) >> 27) & 0x1f)
+/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */
+#define HCS_MAX_SCRATCHPAD(p)   ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f))
 
 /* HCSPARAMS3 - hcs_params3 - bitmasks */
 /* bits 0:7, Max U1 to U0 latency for the roothub ports */
@@ -1288,6 +1290,8 @@ struct xhci_td {
        struct xhci_segment     *start_seg;
        union xhci_trb          *first_trb;
        union xhci_trb          *last_trb;
+       /* actual_length of the URB has already been set */
+       bool                    urb_length_set;
 };
 
 /* xHCI command default timeout value */
@@ -1560,6 +1564,7 @@ struct xhci_hcd {
 #define XHCI_SPURIOUS_WAKEUP   (1 << 18)
 /* For controllers with a broken beyond repair streams implementation */
 #define XHCI_BROKEN_STREAMS    (1 << 19)
+#define XHCI_PME_STUCK_QUIRK   (1 << 20)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
index b9827556455f74dad64adbb4e785f14330f3371a..bfa402cf3a2745492ea5d4fe4cb0f84fc9500ca4 100644 (file)
@@ -151,8 +151,7 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
        }
 
        if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
-               ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
-                                          IRQF_DISABLED);
+               ret = isp1760_udc_register(isp, irq, irqflags);
                if (ret < 0) {
                        isp1760_hcd_unregister(&isp->hcd);
                        return ret;
index eba9b82e2d70c19c5b75dc1b6c3d6a0182ee4d5e..3cb98b1d5d2960171bea26d4fff70e2217d9e7f0 100644 (file)
@@ -1274,7 +1274,7 @@ static void errata2_function(unsigned long data)
        for (slot = 0; slot < 32; slot++)
                if (priv->atl_slots[slot].qh && time_after(jiffies,
                                        priv->atl_slots[slot].timestamp +
-                                       SLOT_TIMEOUT * HZ / 1000)) {
+                                       msecs_to_jiffies(SLOT_TIMEOUT))) {
                        ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
                        if (!FROM_DW0_VALID(ptd.dw0) &&
                                        !FROM_DW3_ACTIVE(ptd.dw3))
@@ -1286,7 +1286,7 @@ static void errata2_function(unsigned long data)
 
        spin_unlock_irqrestore(&priv->lock, spinflags);
 
-       errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+       errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
        add_timer(&errata2_timer);
 }
 
@@ -1336,7 +1336,7 @@ static int isp1760_run(struct usb_hcd *hcd)
                return retval;
 
        setup_timer(&errata2_timer, errata2_function, (unsigned long)hcd);
-       errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+       errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
        add_timer(&errata2_timer);
 
        chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
index 9612d7990565c81a75a5310742c793e85e9b8057..3fc4fe7702533b785bc22ead9fe17939e1f365f8 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 14e1628483d9427a68b83f09e18bee8c735e4364..39db8b603627cae44b86bcbd2d9d028027cbe651 100644 (file)
@@ -79,7 +79,8 @@ config USB_MUSB_TUSB6010
 
 config USB_MUSB_OMAP2PLUS
        tristate "OMAP2430 and onwards"
-       depends on ARCH_OMAP2PLUS && USB && OMAP_CONTROL_PHY
+       depends on ARCH_OMAP2PLUS && USB
+       depends on OMAP_CONTROL_PHY || !OMAP_CONTROL_PHY
        select GENERIC_PHY
 
 config USB_MUSB_AM35X
index e6f4cbfeed9736006e852c306aed7f4839987a95..067920f2d570fb77be332cf16e885bf63e0a352c 100644 (file)
@@ -1969,10 +1969,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                goto fail0;
        }
 
-       pm_runtime_use_autosuspend(musb->controller);
-       pm_runtime_set_autosuspend_delay(musb->controller, 200);
-       pm_runtime_enable(musb->controller);
-
        spin_lock_init(&musb->lock);
        musb->board_set_power = plat->set_power;
        musb->min_power = plat->min_power;
@@ -1991,6 +1987,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        musb_readl = musb_default_readl;
        musb_writel = musb_default_writel;
 
+       /* We need musb_read/write functions initialized for PM */
+       pm_runtime_use_autosuspend(musb->controller);
+       pm_runtime_set_autosuspend_delay(musb->controller, 200);
+       pm_runtime_irq_safe(musb->controller);
+       pm_runtime_enable(musb->controller);
+
        /* The musb_platform_init() call:
         *   - adjusts musb->mregs
         *   - sets the musb->isr
index 53bd0e71d19f02e3582db6ac21d0e617765c0ad1..a900c9877195ad6ef2048ddb8c2813c8e196feed 100644 (file)
@@ -457,12 +457,27 @@ static int dsps_musb_init(struct musb *musb)
        if (IS_ERR(musb->xceiv))
                return PTR_ERR(musb->xceiv);
 
+       musb->phy = devm_phy_get(dev->parent, "usb2-phy");
+
        /* Returns zero if e.g. not clocked */
        rev = dsps_readl(reg_base, wrp->revision);
        if (!rev)
                return -ENODEV;
 
        usb_phy_init(musb->xceiv);
+       if (IS_ERR(musb->phy))  {
+               musb->phy = NULL;
+       } else {
+               ret = phy_init(musb->phy);
+               if (ret < 0)
+                       return ret;
+               ret = phy_power_on(musb->phy);
+               if (ret) {
+                       phy_exit(musb->phy);
+                       return ret;
+               }
+       }
+
        setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
 
        /* Reset the musb */
@@ -502,6 +517,8 @@ static int dsps_musb_exit(struct musb *musb)
 
        del_timer_sync(&glue->timer);
        usb_phy_shutdown(musb->xceiv);
+       phy_power_off(musb->phy);
+       phy_exit(musb->phy);
        debugfs_remove_recursive(glue->dbgfs_root);
 
        return 0;
@@ -610,7 +627,7 @@ static int dsps_musb_reset(struct musb *musb)
        struct device *dev = musb->controller;
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
-       int session_restart = 0;
+       int session_restart = 0, error;
 
        if (glue->sw_babble_enabled)
                session_restart = sw_babble_control(musb);
@@ -624,8 +641,14 @@ static int dsps_musb_reset(struct musb *musb)
                dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset));
                usleep_range(100, 200);
                usb_phy_shutdown(musb->xceiv);
+               error = phy_power_off(musb->phy);
+               if (error)
+                       dev_err(dev, "phy shutdown failed: %i\n", error);
                usleep_range(100, 200);
                usb_phy_init(musb->xceiv);
+               error = phy_power_on(musb->phy);
+               if (error)
+                       dev_err(dev, "phy powerup failed: %i\n", error);
                session_restart = 1;
        }
 
@@ -687,7 +710,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
        struct musb_hdrc_config *config;
        struct platform_device *musb;
        struct device_node *dn = parent->dev.of_node;
-       int ret;
+       int ret, val;
 
        memset(resources, 0, sizeof(resources));
        res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc");
@@ -739,7 +762,10 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
        pdata.mode = get_musb_port_mode(dev);
        /* DT keeps this entry in mA, musb expects it as per USB spec */
        pdata.power = get_int_prop(dn, "mentor,power") / 2;
-       config->multipoint = of_property_read_bool(dn, "mentor,multipoint");
+
+       ret = of_property_read_u32(dn, "mentor,multipoint", &val);
+       if (!ret && val)
+               config->multipoint = true;
 
        ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
        if (ret) {
index 883a9adfdfff5f0c1643036e0be7d7d22d1e73a8..c3d5fc9dfb5bd56f5adc0a3cee337ffd1c31541f 100644 (file)
@@ -2613,7 +2613,7 @@ static const struct hc_driver musb_hc_driver = {
        .description            = "musb-hcd",
        .product_desc           = "MUSB HDRC host driver",
        .hcd_priv_size          = sizeof(struct musb *),
-       .flags                  = HCD_USB2 | HCD_MEMORY,
+       .flags                  = HCD_USB2 | HCD_MEMORY | HCD_BH,
 
        /* not using irq handler or reset hooks from usbcore, since
         * those must be shared with peripheral code for OTG configs
index 763649eb4987d99cafdc8aa5d3eb77590171150d..cc752d8c7773176d1338d5927c7b7c3bf4fc5ccd 100644 (file)
@@ -516,7 +516,7 @@ static int omap2430_probe(struct platform_device *pdev)
        struct omap2430_glue            *glue;
        struct device_node              *np = pdev->dev.of_node;
        struct musb_hdrc_config         *config;
-       int                             ret = -ENOMEM;
+       int                             ret = -ENOMEM, val;
 
        glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
        if (!glue)
@@ -559,7 +559,10 @@ static int omap2430_probe(struct platform_device *pdev)
                of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
                of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
                of_property_read_u32(np, "power", (u32 *)&pdata->power);
-               config->multipoint = of_property_read_bool(np, "multipoint");
+
+               ret = of_property_read_u32(np, "multipoint", &val);
+               if (!ret && val)
+                       config->multipoint = true;
 
                pdata->board_data       = data;
                pdata->config           = config;
index 403fab772724825b16ecfd8446ab9d95386bb1cc..7b3035ff94347a519a9d54f27c45108aaaca0e9f 100644 (file)
@@ -126,6 +126,9 @@ struct phy_control *am335x_get_phy_control(struct device *dev)
                return NULL;
 
        dev = bus_find_device(&platform_bus_type, NULL, node, match);
+       if (!dev)
+               return NULL;
+
        ctrl_usb = dev_get_drvdata(dev);
        if (!ctrl_usb)
                return NULL;
index de83b9d0cd5c39449eb71e237ecd2dfa272cdf8c..ebc99ee076ce337275bbea3869abaa830b007111 100644 (file)
@@ -6,6 +6,7 @@ config USB_RENESAS_USBHS
        tristate 'Renesas USBHS controller'
        depends on USB_GADGET
        depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+       depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in
        default n
        help
          Renesas USBHS is a discrete USB host and peripheral controller chip
index 9374bd2aba20759f4bb4b03d2a9d51058aead9fd..8936a83c96cd60c8a226e0c96a9908c06d356773 100644 (file)
@@ -38,56 +38,51 @@ static int usb_serial_device_match(struct device *dev,
        return 0;
 }
 
-static ssize_t port_number_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct usb_serial_port *port = to_usb_serial_port(dev);
-
-       return sprintf(buf, "%d\n", port->port_number);
-}
-static DEVICE_ATTR_RO(port_number);
-
 static int usb_serial_device_probe(struct device *dev)
 {
        struct usb_serial_driver *driver;
        struct usb_serial_port *port;
+       struct device *tty_dev;
        int retval = 0;
        int minor;
 
        port = to_usb_serial_port(dev);
-       if (!port) {
-               retval = -ENODEV;
-               goto exit;
-       }
+       if (!port)
+               return -ENODEV;
 
        /* make sure suspend/resume doesn't race against port_probe */
        retval = usb_autopm_get_interface(port->serial->interface);
        if (retval)
-               goto exit;
+               return retval;
 
        driver = port->serial->type;
        if (driver->port_probe) {
                retval = driver->port_probe(port);
                if (retval)
-                       goto exit_with_autopm;
+                       goto err_autopm_put;
        }
 
-       retval = device_create_file(dev, &dev_attr_port_number);
-       if (retval) {
-               if (driver->port_remove)
-                       retval = driver->port_remove(port);
-               goto exit_with_autopm;
+       minor = port->minor;
+       tty_dev = tty_register_device(usb_serial_tty_driver, minor, dev);
+       if (IS_ERR(tty_dev)) {
+               retval = PTR_ERR(tty_dev);
+               goto err_port_remove;
        }
 
-       minor = port->minor;
-       tty_register_device(usb_serial_tty_driver, minor, dev);
+       usb_autopm_put_interface(port->serial->interface);
+
        dev_info(&port->serial->dev->dev,
                 "%s converter now attached to ttyUSB%d\n",
                 driver->description, minor);
 
-exit_with_autopm:
+       return 0;
+
+err_port_remove:
+       if (driver->port_remove)
+               driver->port_remove(port);
+err_autopm_put:
        usb_autopm_put_interface(port->serial->interface);
-exit:
+
        return retval;
 }
 
@@ -114,8 +109,6 @@ static int usb_serial_device_remove(struct device *dev)
        minor = port->minor;
        tty_unregister_device(usb_serial_tty_driver, minor);
 
-       device_remove_file(&port->dev, &dev_attr_port_number);
-
        driver = port->serial->type;
        if (driver->port_remove)
                retval = driver->port_remove(port);
index 2d72aa3564a31e9eeade77423ec16de3d743c706..ede4f5fcfadda11dcdb7ab954769f827bd3c312a 100644 (file)
@@ -84,6 +84,10 @@ struct ch341_private {
        u8 line_status; /* active status of modem control inputs */
 };
 
+static void ch341_set_termios(struct tty_struct *tty,
+                             struct usb_serial_port *port,
+                             struct ktermios *old_termios);
+
 static int ch341_control_out(struct usb_device *dev, u8 request,
                             u16 value, u16 index)
 {
@@ -309,19 +313,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct ch341_private *priv = usb_get_serial_port_data(port);
        int r;
 
-       priv->baud_rate = DEFAULT_BAUD_RATE;
-
        r = ch341_configure(serial->dev, priv);
        if (r)
                goto out;
 
-       r = ch341_set_handshake(serial->dev, priv->line_control);
-       if (r)
-               goto out;
-
-       r = ch341_set_baudrate(serial->dev, priv);
-       if (r)
-               goto out;
+       if (tty)
+               ch341_set_termios(tty, port, NULL);
 
        dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__);
        r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
index 29fa1c3d0089bee738ed4f54a8b65d4f82dd0c03..3806e7014199d13c892f32e8a03c1b37e286bddb 100644 (file)
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/tty.h>
 #include <linux/console.h>
@@ -144,6 +145,7 @@ static int usb_console_setup(struct console *co, char *options)
                        init_ldsem(&tty->ldisc_sem);
                        INIT_LIST_HEAD(&tty->tty_files);
                        kref_get(&tty->driver->kref);
+                       __module_get(tty->driver->owner);
                        tty->ops = &usb_console_fake_tty_ops;
                        if (tty_init_termios(tty)) {
                                retval = -ENOMEM;
index f40c856ff758d959318ae4d251eea6cd96f5819a..84ce2d74894c9c3b25c7bcf0185f23887492eb94 100644 (file)
@@ -147,6 +147,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
        { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
        { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
+       { USB_DEVICE(0x16C0, 0x09B0) }, /* Lunatico Seletek */
+       { USB_DEVICE(0x16C0, 0x09B1) }, /* Lunatico Seletek */
        { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
        { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
        { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
index 1ebb351b9e9a59c9dbd90ffda56cae1769de764e..8eb68a31cab6c4021617ca555cd58b086872c112 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 e52409c9be999f817cbdb627f4be8ec6f127cbe6..4e4f46f3c89c025670d42860756f39b2bb62ae24 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 ccf1df7c4b80f3f7a596fa3d1d8904eb64a78db6..54e170dd3dad0cec058e29674b98f685f90274df 100644 (file)
@@ -258,7 +258,8 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
         * character or at least one jiffy.
         */
        period = max_t(unsigned long, (10 * HZ / bps), 1);
-       period = min_t(unsigned long, period, timeout);
+       if (timeout)
+               period = min_t(unsigned long, period, timeout);
 
        dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n",
                                        __func__, jiffies_to_msecs(timeout),
@@ -268,7 +269,7 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
                schedule_timeout_interruptible(period);
                if (signal_pending(current))
                        break;
-               if (time_after(jiffies, expire))
+               if (timeout && time_after(jiffies, expire))
                        break;
        }
 }
index dd97d8b572c336e03c7c4c282fbe7e38c44646a4..4f7e072e4e001e9f7c439114f13b52a77d3250d6 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 ab1d690274ae52b3230f04acbd8194a49f68b7ba..460a40669967855cfeea7c6cc911064822c6882a 100644 (file)
@@ -1284,7 +1284,8 @@ static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port)
        }
 
        /* Initial port termios */
-       mxuport_set_termios(tty, port, NULL);
+       if (tty)
+               mxuport_set_termios(tty, port, NULL);
 
        /*
         * TODO: use RQ_VENDOR_GET_MSR, once we know what it
index 0f872e6b2c878f9b8de56fc6ae0cddda56468589..829604d11f3fa72a6b5bec5580f150c27c513cbf 100644 (file)
@@ -132,6 +132,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define UART_OVERRUN_ERROR             0x40
 #define UART_CTS                       0x80
 
+static void pl2303_set_break(struct usb_serial_port *port, bool enable);
 
 enum pl2303_type {
        TYPE_01,        /* Type 0 and 1 (difference unknown) */
@@ -615,6 +616,7 @@ static void pl2303_close(struct usb_serial_port *port)
 {
        usb_serial_generic_close(port);
        usb_kill_urb(port->interrupt_in_urb);
+       pl2303_set_break(port, false);
 }
 
 static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -741,17 +743,16 @@ static int pl2303_ioctl(struct tty_struct *tty,
        return -ENOIOCTLCMD;
 }
 
-static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
+static void pl2303_set_break(struct usb_serial_port *port, bool enable)
 {
-       struct usb_serial_port *port = tty->driver_data;
        struct usb_serial *serial = port->serial;
        u16 state;
        int result;
 
-       if (break_state == 0)
-               state = BREAK_OFF;
-       else
+       if (enable)
                state = BREAK_ON;
+       else
+               state = BREAK_OFF;
 
        dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
                        state == BREAK_OFF ? "off" : "on");
@@ -763,6 +764,13 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
                dev_err(&port->dev, "error sending break = %d\n", result);
 }
 
+static void pl2303_break_ctl(struct tty_struct *tty, int state)
+{
+       struct usb_serial_port *port = tty->driver_data;
+
+       pl2303_set_break(port, state);
+}
+
 static void pl2303_update_line_status(struct usb_serial_port *port,
                                      unsigned char *data,
                                      unsigned int actual_length)
index 475723c006f955923d255be9abc408c7fd29027d..529066bbc7e81be1bb67e398f58425febef6a8eb 100644 (file)
@@ -687,6 +687,21 @@ static void serial_port_dtr_rts(struct tty_port *port, int on)
                drv->dtr_rts(p, on);
 }
 
+static ssize_t port_number_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+
+       return sprintf(buf, "%u\n", port->port_number);
+}
+static DEVICE_ATTR_RO(port_number);
+
+static struct attribute *usb_serial_port_attrs[] = {
+       &dev_attr_port_number.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(usb_serial_port);
+
 static const struct tty_port_operations serial_port_ops = {
        .carrier_raised         = serial_port_carrier_raised,
        .dtr_rts                = serial_port_dtr_rts,
@@ -902,6 +917,7 @@ static int usb_serial_probe(struct usb_interface *interface,
                port->dev.driver = NULL;
                port->dev.bus = &usb_serial_bus_type;
                port->dev.release = &usb_serial_port_release;
+               port->dev.groups = usb_serial_port_groups;
                device_initialize(&port->dev);
        }
 
@@ -940,8 +956,9 @@ static int usb_serial_probe(struct usb_interface *interface,
                port = serial->port[i];
                if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
                        goto probe_error;
-               buffer_size = max_t(int, serial->type->bulk_out_size,
-                                               usb_endpoint_maxp(endpoint));
+               buffer_size = serial->type->bulk_out_size;
+               if (!buffer_size)
+                       buffer_size = usb_endpoint_maxp(endpoint);
                port->bulk_out_size = buffer_size;
                port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
 
index dbc00e56c7f5c106a67028e1b6da7dfee2c39e5e..c85ea530085f12d86ca691d82122f04e9f2166ae 100644 (file)
@@ -113,6 +113,20 @@ UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
 
+/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
+UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
+               "Initio Corporation",
+               "",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_ATA_1X),
+
+/* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
+UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
+               "JMicron",
+               "JMS539",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_REPORT_OPCODES),
+
 /* Reported-by: Claudio Bizzarri <claudio.bizzarri@gmail.com> */
 UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
                "JMicron",
index d468d02179f4707d308192ed3578665a41ee96f9..5600c33fcadb219e52e8f985bf692c6ff3a1025e 100644 (file)
@@ -889,6 +889,12 @@ static void usb_stor_scan_dwork(struct work_struct *work)
            !(us->fflags & US_FL_SCM_MULT_TARG)) {
                mutex_lock(&us->dev_mutex);
                us->max_lun = usb_stor_Bulk_max_lun(us);
+               /*
+                * Allow proper scanning of devices that present more than 8 LUNs
+                * While not affecting other devices that may need the previous behavior
+                */
+               if (us->max_lun >= 8)
+                       us_to_host(us)->max_lun = us->max_lun+1;
                mutex_unlock(&us->dev_mutex);
        }
        scsi_scan_host(us_to_host(us));
index f88bfdf5b6a036a6bf1aae3b8abe3ec6d944ffe0..2027a27546ef4f7a816c08f7598e9c796e6c5ad7 100644 (file)
@@ -868,12 +868,14 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
                                func = vfio_pci_set_err_trigger;
                        break;
                }
+               break;
        case VFIO_PCI_REQ_IRQ_INDEX:
                switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
                case VFIO_IRQ_SET_ACTION_TRIGGER:
                        func = vfio_pci_set_req_trigger;
                        break;
                }
+               break;
        }
 
        if (!func)
index afa06d28725dad3960aed1df9dd4f9e9ddc53493..2bbfc25e582cb8b334a1ef4083b22da56c48cc65 100644 (file)
@@ -591,11 +591,6 @@ static void handle_rx(struct vhost_net *net)
                         * TODO: support TSO.
                         */
                        iov_iter_advance(&msg.msg_iter, vhost_hlen);
-               } else {
-                       /* It'll come from socket; we'll need to patch
-                        * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
-                        */
-                       iov_iter_advance(&fixup, sizeof(hdr));
                }
                err = sock->ops->recvmsg(NULL, sock, &msg,
                                         sock_len, MSG_DONTWAIT | MSG_TRUNC);
@@ -609,17 +604,25 @@ static void handle_rx(struct vhost_net *net)
                        continue;
                }
                /* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */
-               if (unlikely(vhost_hlen) &&
-                   copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) {
-                       vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
-                              vq->iov->iov_base);
-                       break;
+               if (unlikely(vhost_hlen)) {
+                       if (copy_to_iter(&hdr, sizeof(hdr),
+                                        &fixup) != sizeof(hdr)) {
+                               vq_err(vq, "Unable to write vnet_hdr "
+                                      "at addr %p\n", vq->iov->iov_base);
+                               break;
+                       }
+               } else {
+                       /* Header came from socket; we'll need to patch
+                        * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
+                        */
+                       iov_iter_advance(&fixup, sizeof(hdr));
                }
                /* TODO: Should check and handle checksum. */
 
                num_buffers = cpu_to_vhost16(vq, headcount);
                if (likely(mergeable) &&
-                   copy_to_iter(&num_buffers, 2, &fixup) != 2) {
+                   copy_to_iter(&num_buffers, sizeof num_buffers,
+                                &fixup) != sizeof num_buffers) {
                        vq_err(vq, "Failed num_buffers write");
                        vhost_discard_vq_desc(vq, headcount);
                        break;
index 8d4f3f1ff799fb1d7b4bb5a2184144b515676a2c..71df240a467a10bef98c6314ba8d6031fa8e3bf6 100644 (file)
@@ -1956,10 +1956,9 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
                goto out;
        }
        /*
-        * Now register the TCM vhost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vhost virtual I_T Nexus as active.
         */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index 32c0b6b28097f115f5a701d7a7d59f50d92d147d..9362424c2340490585fe02e4dfe950f53f2097af 100644 (file)
@@ -599,6 +599,9 @@ static int clcdfb_of_get_mode(struct device *dev, struct device_node *endpoint,
 
        len = clcdfb_snprintf_mode(NULL, 0, mode);
        name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
        clcdfb_snprintf_mode(name, len + 1, mode);
        mode->name = name;
 
index 95338593ebf4bc8bfc280bf1567c5fa90d712916..868facdec6384da049eb130097eaf76c994b95d0 100644 (file)
@@ -624,9 +624,6 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
        int num = 0, i, first = 1;
        int ver, rev;
 
-       ver = edid[EDID_STRUCT_VERSION];
-       rev = edid[EDID_STRUCT_REVISION];
-
        mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
        if (mode == NULL)
                return NULL;
@@ -637,6 +634,9 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
                return NULL;
        }
 
+       ver = edid[EDID_STRUCT_VERSION];
+       rev = edid[EDID_STRUCT_REVISION];
+
        *dbsize = 0;
 
        DPRINTK("   Detailed Timings\n");
index 5a2095a98ed868016f0f5283c431b012bf2eac08..12186557a9d4d5030d23dd91453029a3d2cc8a3c 100644 (file)
 #include <video/omapdss.h>
 #include "dss.h"
 
-static struct omap_dss_device *to_dss_device_sysfs(struct device *dev)
+static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = NULL;
-
-       for_each_dss_dev(dssdev) {
-               if (dssdev->dev == dev) {
-                       omap_dss_put_device(dssdev);
-                       return dssdev;
-               }
-       }
-
-       return NULL;
-}
-
-static ssize_t display_name_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
-
        return snprintf(buf, PAGE_SIZE, "%s\n",
                        dssdev->name ?
                        dssdev->name : "");
 }
 
-static ssize_t display_enabled_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
-
        return snprintf(buf, PAGE_SIZE, "%d\n",
                        omapdss_device_is_enabled(dssdev));
 }
 
-static ssize_t display_enabled_store(struct device *dev,
-               struct device_attribute *attr,
+static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
                const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool enable;
 
@@ -90,19 +68,16 @@ static ssize_t display_enabled_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_tear_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        return snprintf(buf, PAGE_SIZE, "%d\n",
                        dssdev->driver->get_te ?
                        dssdev->driver->get_te(dssdev) : 0);
 }
 
-static ssize_t display_tear_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_tear_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool te;
 
@@ -120,10 +95,8 @@ static ssize_t display_tear_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_timings_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        struct omap_video_timings t;
 
        if (!dssdev->driver->get_timings)
@@ -137,10 +110,9 @@ static ssize_t display_timings_show(struct device *dev,
                        t.y_res, t.vfp, t.vbp, t.vsw);
 }
 
-static ssize_t display_timings_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_timings_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        struct omap_video_timings t = dssdev->panel.timings;
        int r, found;
 
@@ -176,10 +148,8 @@ static ssize_t display_timings_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_rotate_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int rotate;
        if (!dssdev->driver->get_rotate)
                return -ENOENT;
@@ -187,10 +157,9 @@ static ssize_t display_rotate_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
 }
 
-static ssize_t display_rotate_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int rot, r;
 
        if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
@@ -207,10 +176,8 @@ static ssize_t display_rotate_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_mirror_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int mirror;
        if (!dssdev->driver->get_mirror)
                return -ENOENT;
@@ -218,10 +185,9 @@ static ssize_t display_mirror_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
 }
 
-static ssize_t display_mirror_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        int r;
        bool mirror;
 
@@ -239,10 +205,8 @@ static ssize_t display_mirror_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_wss_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        unsigned int wss;
 
        if (!dssdev->driver->get_wss)
@@ -253,10 +217,9 @@ static ssize_t display_wss_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
 }
 
-static ssize_t display_wss_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
+static ssize_t display_wss_store(struct omap_dss_device *dssdev,
+       const char *buf, size_t size)
 {
-       struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
        u32 wss;
        int r;
 
@@ -277,50 +240,94 @@ static ssize_t display_wss_store(struct device *dev,
        return size;
 }
 
-static DEVICE_ATTR(display_name, S_IRUGO, display_name_show, NULL);
-static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
+struct display_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct omap_dss_device *, char *);
+       ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
+};
+
+#define DISPLAY_ATTR(_name, _mode, _show, _store) \
+       struct display_attribute display_attr_##_name = \
+       __ATTR(_name, _mode, _show, _store)
+
+static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
+static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
+static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
                display_enabled_show, display_enabled_store);
-static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
                display_tear_show, display_tear_store);
-static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
                display_timings_show, display_timings_store);
-static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
                display_rotate_show, display_rotate_store);
-static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
                display_mirror_show, display_mirror_store);
-static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
+static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
                display_wss_show, display_wss_store);
 
-static const struct attribute *display_sysfs_attrs[] = {
-       &dev_attr_display_name.attr,
-       &dev_attr_enabled.attr,
-       &dev_attr_tear_elim.attr,
-       &dev_attr_timings.attr,
-       &dev_attr_rotate.attr,
-       &dev_attr_mirror.attr,
-       &dev_attr_wss.attr,
+static struct attribute *display_sysfs_attrs[] = {
+       &display_attr_name.attr,
+       &display_attr_display_name.attr,
+       &display_attr_enabled.attr,
+       &display_attr_tear_elim.attr,
+       &display_attr_timings.attr,
+       &display_attr_rotate.attr,
+       &display_attr_mirror.attr,
+       &display_attr_wss.attr,
        NULL
 };
 
+static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev;
+       struct display_attribute *display_attr;
+
+       dssdev = container_of(kobj, struct omap_dss_device, kobj);
+       display_attr = container_of(attr, struct display_attribute, attr);
+
+       if (!display_attr->show)
+               return -ENOENT;
+
+       return display_attr->show(dssdev, buf);
+}
+
+static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
+               const char *buf, size_t size)
+{
+       struct omap_dss_device *dssdev;
+       struct display_attribute *display_attr;
+
+       dssdev = container_of(kobj, struct omap_dss_device, kobj);
+       display_attr = container_of(attr, struct display_attribute, attr);
+
+       if (!display_attr->store)
+               return -ENOENT;
+
+       return display_attr->store(dssdev, buf, size);
+}
+
+static const struct sysfs_ops display_sysfs_ops = {
+       .show = display_attr_show,
+       .store = display_attr_store,
+};
+
+static struct kobj_type display_ktype = {
+       .sysfs_ops = &display_sysfs_ops,
+       .default_attrs = display_sysfs_attrs,
+};
+
 int display_init_sysfs(struct platform_device *pdev)
 {
        struct omap_dss_device *dssdev = NULL;
        int r;
 
        for_each_dss_dev(dssdev) {
-               struct kobject *kobj = &dssdev->dev->kobj;
-
-               r = sysfs_create_files(kobj, display_sysfs_attrs);
+               r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
+                       &pdev->dev.kobj, dssdev->alias);
                if (r) {
                        DSSERR("failed to create sysfs files\n");
-                       goto err;
-               }
-
-               r = sysfs_create_link(&pdev->dev.kobj, kobj, dssdev->alias);
-               if (r) {
-                       sysfs_remove_files(kobj, display_sysfs_attrs);
-
-                       DSSERR("failed to create sysfs display link\n");
+                       omap_dss_put_device(dssdev);
                        goto err;
                }
        }
@@ -338,8 +345,12 @@ void display_uninit_sysfs(struct platform_device *pdev)
        struct omap_dss_device *dssdev = NULL;
 
        for_each_dss_dev(dssdev) {
-               sysfs_remove_link(&pdev->dev.kobj, dssdev->alias);
-               sysfs_remove_files(&dssdev->dev->kobj,
-                               display_sysfs_attrs);
+               if (kobject_name(&dssdev->kobj) == NULL)
+                       continue;
+
+               kobject_del(&dssdev->kobj);
+               kobject_put(&dssdev->kobj);
+
+               memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
        }
 }
index 0413157f3b49c230aaa7a775564086144977803f..6a356e344f82c3d5b594abeeb47c453e868c4f9f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/balloon_compaction.h>
 #include <linux/oom.h>
+#include <linux/wait.h>
 
 /*
  * Balloon device works in 4K page units.  So each page is pointed to by
@@ -334,17 +335,25 @@ static int virtballoon_oom_notify(struct notifier_block *self,
 static int balloon(void *_vballoon)
 {
        struct virtio_balloon *vb = _vballoon;
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
        set_freezable();
        while (!kthread_should_stop()) {
                s64 diff;
 
                try_to_freeze();
-               wait_event_interruptible(vb->config_change,
-                                        (diff = towards_target(vb)) != 0
-                                        || vb->need_stats_update
-                                        || kthread_should_stop()
-                                        || freezing(current));
+
+               add_wait_queue(&vb->config_change, &wait);
+               for (;;) {
+                       if ((diff = towards_target(vb)) != 0 ||
+                           vb->need_stats_update ||
+                           kthread_should_stop() ||
+                           freezing(current))
+                               break;
+                       wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+               }
+               remove_wait_queue(&vb->config_change, &wait);
+
                if (vb->need_stats_update)
                        stats_handle_request(vb);
                if (diff > 0)
@@ -499,6 +508,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
        if (err < 0)
                goto out_oom_notify;
 
+       virtio_device_ready(vdev);
+
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
                err = PTR_ERR(vb->thread);
index cad569890908de40ba4d72edd6562fb87b6e14b5..6010d7ec0a0f899b7b7690d202e9b57c6dbc7193 100644 (file)
@@ -156,22 +156,95 @@ static void vm_get(struct virtio_device *vdev, unsigned offset,
                   void *buf, unsigned len)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       u8 *ptr = buf;
-       int i;
+       void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
+       u8 b;
+       __le16 w;
+       __le32 l;
 
-       for (i = 0; i < len; i++)
-               ptr[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+       if (vm_dev->version == 1) {
+               u8 *ptr = buf;
+               int i;
+
+               for (i = 0; i < len; i++)
+                       ptr[i] = readb(base + offset + i);
+               return;
+       }
+
+       switch (len) {
+       case 1:
+               b = readb(base + offset);
+               memcpy(buf, &b, sizeof b);
+               break;
+       case 2:
+               w = cpu_to_le16(readw(base + offset));
+               memcpy(buf, &w, sizeof w);
+               break;
+       case 4:
+               l = cpu_to_le32(readl(base + offset));
+               memcpy(buf, &l, sizeof l);
+               break;
+       case 8:
+               l = cpu_to_le32(readl(base + offset));
+               memcpy(buf, &l, sizeof l);
+               l = cpu_to_le32(ioread32(base + offset + sizeof l));
+               memcpy(buf + sizeof l, &l, sizeof l);
+               break;
+       default:
+               BUG();
+       }
 }
 
 static void vm_set(struct virtio_device *vdev, unsigned offset,
                   const void *buf, unsigned len)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       const u8 *ptr = buf;
-       int i;
+       void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
+       u8 b;
+       __le16 w;
+       __le32 l;
 
-       for (i = 0; i < len; i++)
-               writeb(ptr[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+       if (vm_dev->version == 1) {
+               const u8 *ptr = buf;
+               int i;
+
+               for (i = 0; i < len; i++)
+                       writeb(ptr[i], base + offset + i);
+
+               return;
+       }
+
+       switch (len) {
+       case 1:
+               memcpy(&b, buf, sizeof b);
+               writeb(b, base + offset);
+               break;
+       case 2:
+               memcpy(&w, buf, sizeof w);
+               writew(le16_to_cpu(w), base + offset);
+               break;
+       case 4:
+               memcpy(&l, buf, sizeof l);
+               writel(le32_to_cpu(l), base + offset);
+               break;
+       case 8:
+               memcpy(&l, buf, sizeof l);
+               writel(le32_to_cpu(l), base + offset);
+               memcpy(&l, buf + sizeof l, sizeof l);
+               writel(le32_to_cpu(l), base + offset + sizeof l);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static u32 vm_generation(struct virtio_device *vdev)
+{
+       struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+
+       if (vm_dev->version == 1)
+               return 0;
+       else
+               return readl(vm_dev->base + VIRTIO_MMIO_CONFIG_GENERATION);
 }
 
 static u8 vm_get_status(struct virtio_device *vdev)
@@ -440,6 +513,7 @@ static const char *vm_bus_name(struct virtio_device *vdev)
 static const struct virtio_config_ops virtio_mmio_config_ops = {
        .get            = vm_get,
        .set            = vm_set,
+       .generation     = vm_generation,
        .get_status     = vm_get_status,
        .set_status     = vm_set_status,
        .reset          = vm_reset,
index 6df940528fd21b0cef8524004645fe472b7f7061..1443b3c391de497c05fe332f1c4cdd067bc5f5c9 100644 (file)
@@ -208,7 +208,8 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
 
        if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) {
                err = request_irq(wdt->irq, wdt_interrupt,
-                                 IRQF_SHARED | IRQF_IRQPOLL,
+                                 IRQF_SHARED | IRQF_IRQPOLL |
+                                 IRQF_NO_SUSPEND,
                                  pdev->name, wdt);
                if (err)
                        return err;
index c8def68d9e4cf30c391fabc36981f96b4cb9d72a..0deaa4f971f5ff1fdfde6d063314a45bd99b9707 100644 (file)
 #define PDC_WDT_MIN_TIMEOUT            1
 #define PDC_WDT_DEF_TIMEOUT            64
 
-static int heartbeat;
+static int heartbeat = PDC_WDT_DEF_TIMEOUT;
 module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
-       "(default = " __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds "
+       "(default=" __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
@@ -191,6 +191,7 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        pdc_wdt->wdt_dev.ops = &pdc_wdt_ops;
        pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK;
        pdc_wdt->wdt_dev.parent = &pdev->dev;
+       watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
        ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
        if (ret < 0) {
@@ -232,7 +233,6 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout);
 
        platform_set_drvdata(pdev, pdc_wdt);
-       watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
        ret = watchdog_register_device(&pdc_wdt->wdt_dev);
        if (ret)
index a87f6df6e85f32993db3907d66f3066c8820a91d..938b987de551bdea7615a701007d0125f9a10d8b 100644 (file)
@@ -133,7 +133,7 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
        u32 reg;
        struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
        void __iomem *wdt_base = mtk_wdt->wdt_base;
-       u32 ret;
+       int ret;
 
        ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
        if (ret < 0)
index b812462083fcaf8d32c215327d28b7c4b7e6e4da..94d96809e686b9ffd1f83c76681c8c3ff0a7cf92 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 2140398a2a8c6b5f521c6250bb56a56ad41c9df7..2ccd3592d41f549967f7597ed86bd77aef8556bf 100644 (file)
@@ -2,7 +2,7 @@ ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 endif
 obj-$(CONFIG_X86)                      += fallback.o
-obj-y  += grant-table.o features.o balloon.o manage.o
+obj-y  += grant-table.o features.o balloon.o manage.o preempt.o
 obj-y  += events/
 obj-y  += xenbus/
 
index 0b52d92cb2e52d03899dd410d8a58e7640c8d8d5..fd933695f2328f29c2493ee751f22230ec68cbb1 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 b4bca2d4a7e53c7675b25d632b560e1369b19020..70fba973a107165c2c29b2104d8f4d438faddc2b 100644 (file)
@@ -526,20 +526,26 @@ static unsigned int __startup_pirq(unsigned int irq)
        pirq_query_unmask(irq);
 
        rc = set_evtchn_to_irq(evtchn, irq);
-       if (rc != 0) {
-               pr_err("irq%d: Failed to set port to irq mapping (%d)\n",
-                      irq, rc);
-               xen_evtchn_close(evtchn);
-               return 0;
-       }
+       if (rc)
+               goto err;
+
        bind_evtchn_to_cpu(evtchn, 0);
        info->evtchn = evtchn;
 
+       rc = xen_evtchn_port_setup(info);
+       if (rc)
+               goto err;
+
 out:
        unmask_evtchn(evtchn);
        eoi_pirq(irq_get_irq_data(irq));
 
        return 0;
+
+err:
+       pr_err("irq%d: Failed to set port to irq mapping (%d)\n", irq, rc);
+       xen_evtchn_close(evtchn);
+       return 0;
 }
 
 static unsigned int startup_pirq(struct irq_data *data)
diff --git a/drivers/xen/preempt.c b/drivers/xen/preempt.c
new file mode 100644 (file)
index 0000000..a1800c1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Preemptible hypercalls
+ *
+ * Copyright (C) 2014 Citrix Systems R&D ltd.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <xen/xen-ops.h>
+
+#ifndef CONFIG_PREEMPT
+
+/*
+ * Some hypercalls issued by the toolstack can take many 10s of
+ * seconds. Allow tasks running hypercalls via the privcmd driver to
+ * be voluntarily preempted even if full kernel preemption is
+ * disabled.
+ *
+ * Such preemptible hypercalls are bracketed by
+ * xen_preemptible_hcall_begin() and xen_preemptible_hcall_end()
+ * calls.
+ */
+
+DEFINE_PER_CPU(bool, xen_in_preemptible_hcall);
+EXPORT_SYMBOL_GPL(xen_in_preemptible_hcall);
+
+asmlinkage __visible void xen_maybe_preempt_hcall(void)
+{
+       if (unlikely(__this_cpu_read(xen_in_preemptible_hcall)
+                    && should_resched())) {
+               /*
+                * Clear flag as we may be rescheduled on a different
+                * cpu.
+                */
+               __this_cpu_write(xen_in_preemptible_hcall, false);
+               _cond_resched();
+               __this_cpu_write(xen_in_preemptible_hcall, true);
+       }
+}
+#endif /* CONFIG_PREEMPT */
index 569a13b9e856de5c3900050d583844f401243e96..59ac71c4a04352d055f40435444e7ccc46debf31 100644 (file)
@@ -56,10 +56,12 @@ static long privcmd_ioctl_hypercall(void __user *udata)
        if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
                return -EFAULT;
 
+       xen_preemptible_hcall_begin();
        ret = privcmd_call(hypercall.op,
                           hypercall.arg[0], hypercall.arg[1],
                           hypercall.arg[2], hypercall.arg[3],
                           hypercall.arg[4]);
+       xen_preemptible_hcall_end();
 
        return ret;
 }
index 46ae0f9f02adcca044734c58f56a93ca12801f85..75fe3d466515a08cf8ec8da7eebafd8c5b903895 100644 (file)
@@ -16,7 +16,7 @@
 #include "conf_space.h"
 #include "conf_space_quirks.h"
 
-static bool permissive;
+bool permissive;
 module_param(permissive, bool, 0644);
 
 /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
index e56c934ad137be00ce34e5099726e31472e86a93..2e1d73d1d5d09393ebf7e2ab21a026b709e5bb5f 100644 (file)
@@ -64,6 +64,8 @@ struct config_field_entry {
        void *data;
 };
 
+extern bool permissive;
+
 #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
 
 /* Add fields to a device - the add_fields macro expects to get a pointer to
index c5ee82587e8cc3b5feb5e594763da576765fd268..2d7369391472fd572dd3f5b837be3a2625ab4a93 100644 (file)
 #include "pciback.h"
 #include "conf_space.h"
 
+struct pci_cmd_info {
+       u16 val;
+};
+
 struct pci_bar_info {
        u32 val;
        u32 len_val;
@@ -20,22 +24,36 @@ struct pci_bar_info {
 #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
 #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
 
-static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+/* Bits guests are allowed to control in permissive mode. */
+#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
+                          PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
+                          PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
+
+static void *command_init(struct pci_dev *dev, int offset)
 {
-       int i;
-       int ret;
-
-       ret = xen_pcibk_read_config_word(dev, offset, value, data);
-       if (!pci_is_enabled(dev))
-               return ret;
-
-       for (i = 0; i < PCI_ROM_RESOURCE; i++) {
-               if (dev->resource[i].flags & IORESOURCE_IO)
-                       *value |= PCI_COMMAND_IO;
-               if (dev->resource[i].flags & IORESOURCE_MEM)
-                       *value |= PCI_COMMAND_MEMORY;
+       struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+       int err;
+
+       if (!cmd)
+               return ERR_PTR(-ENOMEM);
+
+       err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
+       if (err) {
+               kfree(cmd);
+               return ERR_PTR(err);
        }
 
+       return cmd;
+}
+
+static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+{
+       int ret = pci_read_config_word(dev, offset, value);
+       const struct pci_cmd_info *cmd = data;
+
+       *value &= PCI_COMMAND_GUEST;
+       *value |= cmd->val & ~PCI_COMMAND_GUEST;
+
        return ret;
 }
 
@@ -43,6 +61,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
 {
        struct xen_pcibk_dev_data *dev_data;
        int err;
+       u16 val;
+       struct pci_cmd_info *cmd = data;
 
        dev_data = pci_get_drvdata(dev);
        if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
@@ -83,6 +103,19 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
                }
        }
 
+       cmd->val = value;
+
+       if (!permissive && (!dev_data || !dev_data->permissive))
+               return 0;
+
+       /* Only allow the guest to control certain bits. */
+       err = pci_read_config_word(dev, offset, &val);
+       if (err || val == value)
+               return err;
+
+       value &= PCI_COMMAND_GUEST;
+       value |= val & ~PCI_COMMAND_GUEST;
+
        return pci_write_config_word(dev, offset, value);
 }
 
@@ -282,6 +315,8 @@ static const struct config_field header_common[] = {
        {
         .offset    = PCI_COMMAND,
         .size      = 2,
+        .init      = command_init,
+        .release   = bar_release,
         .u.w.read  = command_read,
         .u.w.write = command_write,
        },
index 61653a03a8f5037c12e28c5087e3fd8960342460..42bd55a6c237209c15790876911d8aa31343b043 100644 (file)
@@ -709,12 +709,11 @@ static int prepare_pending_reqs(struct vscsibk_info *info,
 static int scsiback_do_cmd_fn(struct vscsibk_info *info)
 {
        struct vscsiif_back_ring *ring = &info->ring;
-       struct vscsiif_request *ring_req;
+       struct vscsiif_request ring_req;
        struct vscsibk_pend *pending_req;
        RING_IDX rc, rp;
        int err, more_to_do;
        uint32_t result;
-       uint8_t act;
 
        rc = ring->req_cons;
        rp = ring->sring->req_prod;
@@ -735,11 +734,10 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                if (!pending_req)
                        return 1;
 
-               ring_req = RING_GET_REQUEST(ring, rc);
+               ring_req = *RING_GET_REQUEST(ring, rc);
                ring->req_cons = ++rc;
 
-               act = ring_req->act;
-               err = prepare_pending_reqs(info, ring_req, pending_req);
+               err = prepare_pending_reqs(info, &ring_req, pending_req);
                if (err) {
                        switch (err) {
                        case -ENODEV:
@@ -755,9 +753,9 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                        return 1;
                }
 
-               switch (act) {
+               switch (ring_req.act) {
                case VSCSIIF_ACT_SCSI_CDB:
-                       if (scsiback_gnttab_data_map(ring_req, pending_req)) {
+                       if (scsiback_gnttab_data_map(&ring_req, pending_req)) {
                                scsiback_fast_flush_area(pending_req);
                                scsiback_do_resp_with_sense(NULL,
                                        DRIVER_ERROR << 24, 0, pending_req);
@@ -768,7 +766,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
                        break;
                case VSCSIIF_ACT_SCSI_ABORT:
                        scsiback_device_action(pending_req, TMR_ABORT_TASK,
-                               ring_req->ref_rqid);
+                               ring_req.ref_rqid);
                        break;
                case VSCSIIF_ACT_SCSI_RESET:
                        scsiback_device_action(pending_req, TMR_LUN_RESET, 0);
@@ -1661,11 +1659,8 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg,
                         name);
                goto out;
        }
-       /*
-        * Now register the TCM pvscsi virtual I_T Nexus as active with the
-        * call to __transport_register_session()
-        */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       /* Now register the TCM pvscsi virtual I_T Nexus as active. */
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index d2468bf95669850520a2a0dc852b1185c5234c7b..a91795e01a7ff0c0e85abf1bdf69f3d1d828b231 100644 (file)
@@ -699,8 +699,10 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
        boff = tmp % bsize;
        if (boff) {
                bh = affs_bread_ino(inode, bidx, 0);
-               if (IS_ERR(bh))
-                       return PTR_ERR(bh);
+               if (IS_ERR(bh)) {
+                       written = PTR_ERR(bh);
+                       goto err_first_bh;
+               }
                tmp = min(bsize - boff, to - from);
                BUG_ON(boff + tmp > bsize || tmp > bsize);
                memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
@@ -712,14 +714,16 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                bidx++;
        } else if (bidx) {
                bh = affs_bread_ino(inode, bidx - 1, 0);
-               if (IS_ERR(bh))
-                       return PTR_ERR(bh);
+               if (IS_ERR(bh)) {
+                       written = PTR_ERR(bh);
+                       goto err_first_bh;
+               }
        }
        while (from + bsize <= to) {
                prev_bh = bh;
                bh = affs_getemptyblk_ino(inode, bidx);
                if (IS_ERR(bh))
-                       goto out;
+                       goto err_bh;
                memcpy(AFFS_DATA(bh), data + from, bsize);
                if (buffer_new(bh)) {
                        AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
@@ -751,7 +755,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                prev_bh = bh;
                bh = affs_bread_ino(inode, bidx, 1);
                if (IS_ERR(bh))
-                       goto out;
+                       goto err_bh;
                tmp = min(bsize, to - from);
                BUG_ON(tmp > bsize);
                memcpy(AFFS_DATA(bh), data + from, tmp);
@@ -790,12 +794,13 @@ done:
        if (tmp > inode->i_size)
                inode->i_size = AFFS_I(inode)->mmu_private = tmp;
 
+err_first_bh:
        unlock_page(page);
        page_cache_release(page);
 
        return written;
 
-out:
+err_bh:
        bh = prev_bh;
        if (!written)
                written = PTR_ERR(bh);
index 993642199326a757f55c78dbc2722ecc2b409b60..6d67f32e648df72bc5f5b5d707ff39ce8fa4302b 100644 (file)
@@ -1645,14 +1645,14 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 
        parent_nritems = btrfs_header_nritems(parent);
        blocksize = root->nodesize;
-       end_slot = parent_nritems;
+       end_slot = parent_nritems - 1;
 
-       if (parent_nritems == 1)
+       if (parent_nritems <= 1)
                return 0;
 
        btrfs_set_lock_blocking(parent);
 
-       for (i = start_slot; i < end_slot; i++) {
+       for (i = start_slot; i <= end_slot; i++) {
                int close = 1;
 
                btrfs_node_key(parent, &disk_key, i);
@@ -1669,7 +1669,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                        other = btrfs_node_blockptr(parent, i - 1);
                        close = close_blocks(blocknr, other, blocksize);
                }
-               if (!close && i < end_slot - 2) {
+               if (!close && i < end_slot) {
                        other = btrfs_node_blockptr(parent, i + 1);
                        close = close_blocks(blocknr, other, blocksize);
                }
index 84c3b00f3de8eedf47ba3bec71939a5fba1f90a0..f9c89cae39ee41fd6ae37bbc36178f8eb9093044 100644 (file)
@@ -3387,6 +3387,8 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                    struct btrfs_root *root);
+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root);
 int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr);
 int btrfs_free_block_groups(struct btrfs_fs_info *info);
 int btrfs_read_block_groups(struct btrfs_root *root);
@@ -3909,6 +3911,9 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
                                    loff_t actual_len, u64 *alloc_hint);
 int btrfs_inode_check_errors(struct inode *inode);
 extern const struct dentry_operations btrfs_dentry_operations;
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+void btrfs_test_inode_set_ops(struct inode *inode);
+#endif
 
 /* ioctl.c */
 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
index f79f38542a737631e191e08aed6b50d4a940f964..639f2663ed3f8f40dc925451618702632e8b9109 100644 (file)
@@ -3921,7 +3921,7 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
        }
        if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key)
                        + sizeof(struct btrfs_chunk)) {
-               printk(KERN_ERR "BTRFS: system chunk array too small %u < %lu\n",
+               printk(KERN_ERR "BTRFS: system chunk array too small %u < %zu\n",
                                btrfs_super_sys_array_size(sb),
                                sizeof(struct btrfs_disk_key)
                                + sizeof(struct btrfs_chunk));
index 571f402d3fc46e5f0205451e85a7b78f3cc16b50..8b353ad02f034a9307e1da5d8923aff6b43a0dcb 100644 (file)
@@ -3208,6 +3208,8 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
                return 0;
        }
 
+       if (trans->aborted)
+               return 0;
 again:
        inode = lookup_free_space_inode(root, block_group, path);
        if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
@@ -3243,6 +3245,20 @@ again:
         */
        BTRFS_I(inode)->generation = 0;
        ret = btrfs_update_inode(trans, root, inode);
+       if (ret) {
+               /*
+                * So theoretically we could recover from this, simply set the
+                * super cache generation to 0 so we know to invalidate the
+                * cache, but then we'd have to keep track of the block groups
+                * that fail this way so we know we _have_ to reset this cache
+                * before the next commit or risk reading stale cache.  So to
+                * limit our exposure to horrible edge cases lets just abort the
+                * transaction, this only happens in really bad situations
+                * anyway.
+                */
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_put;
+       }
        WARN_ON(ret);
 
        if (i_size_read(inode) > 0) {
@@ -3309,6 +3325,32 @@ out:
        return ret;
 }
 
+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root)
+{
+       struct btrfs_block_group_cache *cache, *tmp;
+       struct btrfs_transaction *cur_trans = trans->transaction;
+       struct btrfs_path *path;
+
+       if (list_empty(&cur_trans->dirty_bgs) ||
+           !btrfs_test_opt(root, SPACE_CACHE))
+               return 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /* Could add new block groups, use _safe just in case */
+       list_for_each_entry_safe(cache, tmp, &cur_trans->dirty_bgs,
+                                dirty_list) {
+               if (cache->disk_cache_state == BTRFS_DC_CLEAR)
+                       cache_save_setup(cache, trans, path);
+       }
+
+       btrfs_free_path(path);
+       return 0;
+}
+
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root)
 {
@@ -5094,7 +5136,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        num_bytes = ALIGN(num_bytes, root->sectorsize);
 
        spin_lock(&BTRFS_I(inode)->lock);
-       BTRFS_I(inode)->outstanding_extents++;
+       nr_extents = (unsigned)div64_u64(num_bytes +
+                                        BTRFS_MAX_EXTENT_SIZE - 1,
+                                        BTRFS_MAX_EXTENT_SIZE);
+       BTRFS_I(inode)->outstanding_extents += nr_extents;
+       nr_extents = 0;
 
        if (BTRFS_I(inode)->outstanding_extents >
            BTRFS_I(inode)->reserved_extents)
@@ -5239,6 +5285,9 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
        if (dropped > 0)
                to_free += btrfs_calc_trans_metadata_size(root, dropped);
 
+       if (btrfs_test_is_dummy_root(root))
+               return;
+
        trace_btrfs_space_reservation(root->fs_info, "delalloc",
                                      btrfs_ino(inode), to_free, 0);
        if (root->fs_info->quota_enabled) {
index c7233ff1d533b653b8b9e7f29e022e9126e5f38a..d688cfe5d4962ddf626e97a36fc8136edd7922b9 100644 (file)
@@ -4968,6 +4968,12 @@ static int release_extent_buffer(struct extent_buffer *eb)
 
                /* Should be safe to release our pages at this point */
                btrfs_release_extent_buffer_page(eb);
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+               if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))) {
+                       __free_extent_buffer(eb);
+                       return 1;
+               }
+#endif
                call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
                return 1;
        }
index b78bbbac900db833e54fc63bdbff8bae365225f3..30982bbd31c30c2b154836b0f51b94c37e22923c 100644 (file)
@@ -1811,22 +1811,10 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
        mutex_unlock(&inode->i_mutex);
 
        /*
-        * we want to make sure fsync finds this change
-        * but we haven't joined a transaction running right now.
-        *
-        * Later on, someone is sure to update the inode and get the
-        * real transid recorded.
-        *
-        * We set last_trans now to the fs_info generation + 1,
-        * this will either be one more than the running transaction
-        * or the generation used for the next transaction if there isn't
-        * one running right now.
-        *
         * We also have to set last_sub_trans to the current log transid,
         * otherwise subsequent syncs to a file that's been synced in this
         * transaction will appear to have already occured.
         */
-       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
        BTRFS_I(inode)->last_sub_trans = root->log_transid;
        if (num_written > 0) {
                err = generic_write_sync(file, pos, num_written);
@@ -1959,25 +1947,37 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        atomic_inc(&root->log_batch);
 
        /*
-        * check the transaction that last modified this inode
-        * and see if its already been committed
-        */
-       if (!BTRFS_I(inode)->last_trans) {
-               mutex_unlock(&inode->i_mutex);
-               goto out;
-       }
-
-       /*
-        * if the last transaction that changed this file was before
-        * the current transaction, we can bail out now without any
-        * syncing
+        * If the last transaction that changed this file was before the current
+        * transaction and we have the full sync flag set in our inode, we can
+        * bail out now without any syncing.
+        *
+        * Note that we can't bail out if the full sync flag isn't set. This is
+        * because when the full sync flag is set we start all ordered extents
+        * and wait for them to fully complete - when they complete they update
+        * the inode's last_trans field through:
+        *
+        *     btrfs_finish_ordered_io() ->
+        *         btrfs_update_inode_fallback() ->
+        *             btrfs_update_inode() ->
+        *                 btrfs_set_inode_last_trans()
+        *
+        * So we are sure that last_trans is up to date and can do this check to
+        * bail out safely. For the fast path, when the full sync flag is not
+        * set in our inode, we can not do it because we start only our ordered
+        * extents and don't wait for them to complete (that is when
+        * btrfs_finish_ordered_io runs), so here at this point their last_trans
+        * value might be less than or equals to fs_info->last_trans_committed,
+        * and setting a speculative last_trans for an inode when a buffered
+        * write is made (such as fs_info->generation + 1 for example) would not
+        * be reliable since after setting the value and before fsync is called
+        * any number of transactions can start and commit (transaction kthread
+        * commits the current transaction periodically), and a transaction
+        * commit does not start nor waits for ordered extents to complete.
         */
        smp_mb();
        if (btrfs_inode_in_log(inode, root->fs_info->generation) ||
-           BTRFS_I(inode)->last_trans <=
-           root->fs_info->last_trans_committed) {
-               BTRFS_I(inode)->last_trans = 0;
-
+           (full_sync && BTRFS_I(inode)->last_trans <=
+            root->fs_info->last_trans_committed)) {
                /*
                 * We'v had everything committed since the last time we were
                 * modified so clear this flag in case it was set for whatever
@@ -2275,6 +2275,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        bool same_page;
        bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
        u64 ino_size;
+       bool truncated_page = false;
+       bool updated_inode = false;
 
        ret = btrfs_wait_ordered_range(inode, offset, len);
        if (ret)
@@ -2306,13 +2308,18 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
         * entire page.
         */
        if (same_page && len < PAGE_CACHE_SIZE) {
-               if (offset < ino_size)
+               if (offset < ino_size) {
+                       truncated_page = true;
                        ret = btrfs_truncate_page(inode, offset, len, 0);
+               } else {
+                       ret = 0;
+               }
                goto out_only_mutex;
        }
 
        /* zero back part of the first page */
        if (offset < ino_size) {
+               truncated_page = true;
                ret = btrfs_truncate_page(inode, offset, 0, 0);
                if (ret) {
                        mutex_unlock(&inode->i_mutex);
@@ -2348,6 +2355,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                if (!ret) {
                        /* zero the front end of the last page */
                        if (tail_start + tail_len < ino_size) {
+                               truncated_page = true;
                                ret = btrfs_truncate_page(inode,
                                                tail_start + tail_len, 0, 1);
                                if (ret)
@@ -2357,8 +2365,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        }
 
        if (lockend < lockstart) {
-               mutex_unlock(&inode->i_mutex);
-               return 0;
+               ret = 0;
+               goto out_only_mutex;
        }
 
        while (1) {
@@ -2506,6 +2514,7 @@ out_trans:
 
        trans->block_rsv = &root->fs_info->trans_block_rsv;
        ret = btrfs_update_inode(trans, root, inode);
+       updated_inode = true;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root);
 out_free:
@@ -2515,6 +2524,22 @@ out:
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                             &cached_state, GFP_NOFS);
 out_only_mutex:
+       if (!updated_inode && truncated_page && !ret && !err) {
+               /*
+                * If we only end up zeroing part of a page, we still need to
+                * update the inode item, so that all the time fields are
+                * updated as well as the necessary btrfs inode in memory fields
+                * for detecting, at fsync time, if the inode isn't yet in the
+                * log tree or it's there but not up to date.
+                */
+               trans = btrfs_start_transaction(root, 1);
+               if (IS_ERR(trans)) {
+                       err = PTR_ERR(trans);
+               } else {
+                       err = btrfs_update_inode(trans, root, inode);
+                       ret = btrfs_end_transaction(trans, root);
+               }
+       }
        mutex_unlock(&inode->i_mutex);
        if (ret && !err)
                err = ret;
index a85c23dfcddbcfd992069811f24b116d74e4dc21..d2e732d7af524640bc2c197da3e7123182b4537e 100644 (file)
@@ -108,6 +108,13 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
 
 static int btrfs_dirty_inode(struct inode *inode);
 
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+void btrfs_test_inode_set_ops(struct inode *inode)
+{
+       BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+}
+#endif
+
 static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
                                     struct inode *inode,  struct inode *dir,
                                     const struct qstr *qstr)
@@ -1542,30 +1549,17 @@ static void btrfs_split_extent_hook(struct inode *inode,
                u64 new_size;
 
                /*
-                * We need the largest size of the remaining extent to see if we
-                * need to add a new outstanding extent.  Think of the following
-                * case
-                *
-                * [MEAX_EXTENT_SIZEx2 - 4k][4k]
-                *
-                * The new_size would just be 4k and we'd think we had enough
-                * outstanding extents for this if we only took one side of the
-                * split, same goes for the other direction.  We need to see if
-                * the larger size still is the same amount of extents as the
-                * original size, because if it is we need to add a new
-                * outstanding extent.  But if we split up and the larger size
-                * is less than the original then we are good to go since we've
-                * already accounted for the extra extent in our original
-                * accounting.
+                * See the explanation in btrfs_merge_extent_hook, the same
+                * applies here, just in reverse.
                 */
                new_size = orig->end - split + 1;
-               if ((split - orig->start) > new_size)
-                       new_size = split - orig->start;
-
-               num_extents = div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
+               num_extents = div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
                                        BTRFS_MAX_EXTENT_SIZE);
-               if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
-                             BTRFS_MAX_EXTENT_SIZE) < num_extents)
+               new_size = split - orig->start;
+               num_extents += div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
+                                       BTRFS_MAX_EXTENT_SIZE);
+               if (div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1,
+                             BTRFS_MAX_EXTENT_SIZE) >= num_extents)
                        return;
        }
 
@@ -1591,8 +1585,10 @@ static void btrfs_merge_extent_hook(struct inode *inode,
        if (!(other->state & EXTENT_DELALLOC))
                return;
 
-       old_size = other->end - other->start + 1;
-       new_size = old_size + (new->end - new->start + 1);
+       if (new->start > other->start)
+               new_size = new->end - other->start + 1;
+       else
+               new_size = other->end - new->start + 1;
 
        /* we're not bigger than the max, unreserve the space and go */
        if (new_size <= BTRFS_MAX_EXTENT_SIZE) {
@@ -1603,13 +1599,32 @@ static void btrfs_merge_extent_hook(struct inode *inode,
        }
 
        /*
-        * If we grew by another max_extent, just return, we want to keep that
-        * reserved amount.
+        * We have to add up either side to figure out how many extents were
+        * accounted for before we merged into one big extent.  If the number of
+        * extents we accounted for is <= the amount we need for the new range
+        * then we can return, otherwise drop.  Think of it like this
+        *
+        * [ 4k][MAX_SIZE]
+        *
+        * So we've grown the extent by a MAX_SIZE extent, this would mean we
+        * need 2 outstanding extents, on one side we have 1 and the other side
+        * we have 1 so they are == and we can return.  But in this case
+        *
+        * [MAX_SIZE+4k][MAX_SIZE+4k]
+        *
+        * Each range on their own accounts for 2 extents, but merged together
+        * they are only 3 extents worth of accounting, so we need to drop in
+        * this case.
         */
+       old_size = other->end - other->start + 1;
        num_extents = div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
                                BTRFS_MAX_EXTENT_SIZE);
+       old_size = new->end - new->start + 1;
+       num_extents += div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1,
+                                BTRFS_MAX_EXTENT_SIZE);
+
        if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1,
-                     BTRFS_MAX_EXTENT_SIZE) > num_extents)
+                     BTRFS_MAX_EXTENT_SIZE) >= num_extents)
                return;
 
        spin_lock(&BTRFS_I(inode)->lock);
@@ -1686,6 +1701,10 @@ static void btrfs_set_bit_hook(struct inode *inode,
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
 
+               /* For sanity tests */
+               if (btrfs_test_is_dummy_root(root))
+                       return;
+
                __percpu_counter_add(&root->fs_info->delalloc_bytes, len,
                                     root->fs_info->delalloc_batch);
                spin_lock(&BTRFS_I(inode)->lock);
@@ -1741,6 +1760,10 @@ static void btrfs_clear_bit_hook(struct inode *inode,
                    root != root->fs_info->tree_root)
                        btrfs_delalloc_release_metadata(inode, len);
 
+               /* For sanity tests. */
+               if (btrfs_test_is_dummy_root(root))
+                       return;
+
                if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
                    && do_list && !(state->state & EXTENT_NORESERVE))
                        btrfs_free_reserved_data_space(inode, len);
@@ -7213,7 +7236,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        u64 start = iblock << inode->i_blkbits;
        u64 lockstart, lockend;
        u64 len = bh_result->b_size;
-       u64 orig_len = len;
+       u64 *outstanding_extents = NULL;
        int unlock_bits = EXTENT_LOCKED;
        int ret = 0;
 
@@ -7225,6 +7248,16 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        lockstart = start;
        lockend = start + len - 1;
 
+       if (current->journal_info) {
+               /*
+                * Need to pull our outstanding extents and set journal_info to NULL so
+                * that anything that needs to check if there's a transction doesn't get
+                * confused.
+                */
+               outstanding_extents = current->journal_info;
+               current->journal_info = NULL;
+       }
+
        /*
         * If this errors out it's because we couldn't invalidate pagecache for
         * this range and we need to fallback to buffered.
@@ -7285,7 +7318,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
            ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) &&
             em->block_start != EXTENT_MAP_HOLE)) {
                int type;
-               int ret;
                u64 block_start, orig_start, orig_block_len, ram_bytes;
 
                if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
@@ -7349,11 +7381,20 @@ unlock:
                if (start + len > i_size_read(inode))
                        i_size_write(inode, start + len);
 
-               if (len < orig_len) {
+               /*
+                * If we have an outstanding_extents count still set then we're
+                * within our reservation, otherwise we need to adjust our inode
+                * counter appropriately.
+                */
+               if (*outstanding_extents) {
+                       (*outstanding_extents)--;
+               } else {
                        spin_lock(&BTRFS_I(inode)->lock);
                        BTRFS_I(inode)->outstanding_extents++;
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
+
+               current->journal_info = outstanding_extents;
                btrfs_free_reserved_data_space(inode, len);
        }
 
@@ -7377,6 +7418,8 @@ unlock:
 unlock_err:
        clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                         unlock_bits, 1, 0, &cached_state, GFP_NOFS);
+       if (outstanding_extents)
+               current->journal_info = outstanding_extents;
        return ret;
 }
 
@@ -8076,6 +8119,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       u64 outstanding_extents = 0;
        size_t count = 0;
        int flags = 0;
        bool wakeup = true;
@@ -8113,6 +8157,16 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                ret = btrfs_delalloc_reserve_space(inode, count);
                if (ret)
                        goto out;
+               outstanding_extents = div64_u64(count +
+                                               BTRFS_MAX_EXTENT_SIZE - 1,
+                                               BTRFS_MAX_EXTENT_SIZE);
+
+               /*
+                * We need to know how many extents we reserved so that we can
+                * do the accounting properly if we go over the number we
+                * originally calculated.  Abuse current->journal_info for this.
+                */
+               current->journal_info = &outstanding_extents;
        } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
                                     &BTRFS_I(inode)->runtime_flags)) {
                inode_dio_done(inode);
@@ -8125,6 +8179,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                        iter, offset, btrfs_get_blocks_direct, NULL,
                        btrfs_submit_direct, flags);
        if (rw & WRITE) {
+               current->journal_info = NULL;
                if (ret < 0 && ret != -EIOCBQUEUED)
                        btrfs_delalloc_release_space(inode, count);
                else if (ret >= 0 && (size_t)ret < count)
index 534544e08f769486a97c3c7f3719bed982500783..157cc54fc63486e485a95bf6d8d6da692ef171ca 100644 (file)
@@ -452,9 +452,7 @@ void btrfs_get_logged_extents(struct inode *inode,
                        continue;
                if (entry_end(ordered) <= start)
                        break;
-               if (!list_empty(&ordered->log_list))
-                       continue;
-               if (test_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
+               if (test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
                        continue;
                list_add(&ordered->log_list, logged_list);
                atomic_inc(&ordered->refs);
@@ -511,8 +509,7 @@ void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans,
                wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE,
                                                   &ordered->flags));
 
-               if (!test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
-                       list_add_tail(&ordered->trans_list, &trans->ordered);
+               list_add_tail(&ordered->trans_list, &trans->ordered);
                spin_lock_irq(&log->log_extents_lock[index]);
        }
        spin_unlock_irq(&log->log_extents_lock[index]);
index 97159a8e91d40b24ca1a8f6367892ecf2ad8b960..058c79eecbfb96825918a370e3f78d926b49b098 100644 (file)
@@ -1259,7 +1259,7 @@ static int comp_oper(struct btrfs_qgroup_operation *oper1,
        if (oper1->seq < oper2->seq)
                return -1;
        if (oper1->seq > oper2->seq)
-               return -1;
+               return 1;
        if (oper1->ref_root < oper2->ref_root)
                return -1;
        if (oper1->ref_root > oper2->ref_root)
index fe5857223515d14753c1f75ce60c2c12e16a3e67..d6033f540cc75cfb49ddbe5f07689d67fdefc492 100644 (file)
@@ -230,6 +230,7 @@ struct pending_dir_move {
        u64 parent_ino;
        u64 ino;
        u64 gen;
+       bool is_orphan;
        struct list_head update_refs;
 };
 
@@ -2984,7 +2985,8 @@ static int add_pending_dir_move(struct send_ctx *sctx,
                                u64 ino_gen,
                                u64 parent_ino,
                                struct list_head *new_refs,
-                               struct list_head *deleted_refs)
+                               struct list_head *deleted_refs,
+                               const bool is_orphan)
 {
        struct rb_node **p = &sctx->pending_dir_moves.rb_node;
        struct rb_node *parent = NULL;
@@ -2999,6 +3001,7 @@ static int add_pending_dir_move(struct send_ctx *sctx,
        pm->parent_ino = parent_ino;
        pm->ino = ino;
        pm->gen = ino_gen;
+       pm->is_orphan = is_orphan;
        INIT_LIST_HEAD(&pm->list);
        INIT_LIST_HEAD(&pm->update_refs);
        RB_CLEAR_NODE(&pm->node);
@@ -3131,16 +3134,20 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
        rmdir_ino = dm->rmdir_ino;
        free_waiting_dir_move(sctx, dm);
 
-       ret = get_first_ref(sctx->parent_root, pm->ino,
-                           &parent_ino, &parent_gen, name);
-       if (ret < 0)
-               goto out;
-
-       ret = get_cur_path(sctx, parent_ino, parent_gen,
-                          from_path);
-       if (ret < 0)
-               goto out;
-       ret = fs_path_add_path(from_path, name);
+       if (pm->is_orphan) {
+               ret = gen_unique_name(sctx, pm->ino,
+                                     pm->gen, from_path);
+       } else {
+               ret = get_first_ref(sctx->parent_root, pm->ino,
+                                   &parent_ino, &parent_gen, name);
+               if (ret < 0)
+                       goto out;
+               ret = get_cur_path(sctx, parent_ino, parent_gen,
+                                  from_path);
+               if (ret < 0)
+                       goto out;
+               ret = fs_path_add_path(from_path, name);
+       }
        if (ret < 0)
                goto out;
 
@@ -3150,7 +3157,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
                LIST_HEAD(deleted_refs);
                ASSERT(ancestor > BTRFS_FIRST_FREE_OBJECTID);
                ret = add_pending_dir_move(sctx, pm->ino, pm->gen, ancestor,
-                                          &pm->update_refs, &deleted_refs);
+                                          &pm->update_refs, &deleted_refs,
+                                          pm->is_orphan);
                if (ret < 0)
                        goto out;
                if (rmdir_ino) {
@@ -3283,6 +3291,127 @@ out:
        return ret;
 }
 
+/*
+ * We might need to delay a directory rename even when no ancestor directory
+ * (in the send root) with a higher inode number than ours (sctx->cur_ino) was
+ * renamed. This happens when we rename a directory to the old name (the name
+ * in the parent root) of some other unrelated directory that got its rename
+ * delayed due to some ancestor with higher number that got renamed.
+ *
+ * Example:
+ *
+ * Parent snapshot:
+ * .                                       (ino 256)
+ * |---- a/                                (ino 257)
+ * |     |---- file                        (ino 260)
+ * |
+ * |---- b/                                (ino 258)
+ * |---- c/                                (ino 259)
+ *
+ * Send snapshot:
+ * .                                       (ino 256)
+ * |---- a/                                (ino 258)
+ * |---- x/                                (ino 259)
+ *       |---- y/                          (ino 257)
+ *             |----- file                 (ino 260)
+ *
+ * Here we can not rename 258 from 'b' to 'a' without the rename of inode 257
+ * from 'a' to 'x/y' happening first, which in turn depends on the rename of
+ * inode 259 from 'c' to 'x'. So the order of rename commands the send stream
+ * must issue is:
+ *
+ * 1 - rename 259 from 'c' to 'x'
+ * 2 - rename 257 from 'a' to 'x/y'
+ * 3 - rename 258 from 'b' to 'a'
+ *
+ * Returns 1 if the rename of sctx->cur_ino needs to be delayed, 0 if it can
+ * be done right away and < 0 on error.
+ */
+static int wait_for_dest_dir_move(struct send_ctx *sctx,
+                                 struct recorded_ref *parent_ref,
+                                 const bool is_orphan)
+{
+       struct btrfs_path *path;
+       struct btrfs_key key;
+       struct btrfs_key di_key;
+       struct btrfs_dir_item *di;
+       u64 left_gen;
+       u64 right_gen;
+       int ret = 0;
+
+       if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves))
+               return 0;
+
+       path = alloc_path_for_send();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = parent_ref->dir;
+       key.type = BTRFS_DIR_ITEM_KEY;
+       key.offset = btrfs_name_hash(parent_ref->name, parent_ref->name_len);
+
+       ret = btrfs_search_slot(NULL, sctx->parent_root, &key, path, 0, 0);
+       if (ret < 0) {
+               goto out;
+       } else if (ret > 0) {
+               ret = 0;
+               goto out;
+       }
+
+       di = btrfs_match_dir_item_name(sctx->parent_root, path,
+                                      parent_ref->name, parent_ref->name_len);
+       if (!di) {
+               ret = 0;
+               goto out;
+       }
+       /*
+        * di_key.objectid has the number of the inode that has a dentry in the
+        * parent directory with the same name that sctx->cur_ino is being
+        * renamed to. We need to check if that inode is in the send root as
+        * well and if it is currently marked as an inode with a pending rename,
+        * if it is, we need to delay the rename of sctx->cur_ino as well, so
+        * that it happens after that other inode is renamed.
+        */
+       btrfs_dir_item_key_to_cpu(path->nodes[0], di, &di_key);
+       if (di_key.type != BTRFS_INODE_ITEM_KEY) {
+               ret = 0;
+               goto out;
+       }
+
+       ret = get_inode_info(sctx->parent_root, di_key.objectid, NULL,
+                            &left_gen, NULL, NULL, NULL, NULL);
+       if (ret < 0)
+               goto out;
+       ret = get_inode_info(sctx->send_root, di_key.objectid, NULL,
+                            &right_gen, NULL, NULL, NULL, NULL);
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       ret = 0;
+               goto out;
+       }
+
+       /* Different inode, no need to delay the rename of sctx->cur_ino */
+       if (right_gen != left_gen) {
+               ret = 0;
+               goto out;
+       }
+
+       if (is_waiting_for_move(sctx, di_key.objectid)) {
+               ret = add_pending_dir_move(sctx,
+                                          sctx->cur_ino,
+                                          sctx->cur_inode_gen,
+                                          di_key.objectid,
+                                          &sctx->new_refs,
+                                          &sctx->deleted_refs,
+                                          is_orphan);
+               if (!ret)
+                       ret = 1;
+       }
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 static int wait_for_parent_move(struct send_ctx *sctx,
                                struct recorded_ref *parent_ref)
 {
@@ -3349,7 +3478,8 @@ out:
                                           sctx->cur_inode_gen,
                                           ino,
                                           &sctx->new_refs,
-                                          &sctx->deleted_refs);
+                                          &sctx->deleted_refs,
+                                          false);
                if (!ret)
                        ret = 1;
        }
@@ -3372,6 +3502,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
        int did_overwrite = 0;
        int is_orphan = 0;
        u64 last_dir_ino_rm = 0;
+       bool can_rename = true;
 
 verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
 
@@ -3490,12 +3621,22 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                        }
                }
 
+               if (S_ISDIR(sctx->cur_inode_mode) && sctx->parent_root) {
+                       ret = wait_for_dest_dir_move(sctx, cur, is_orphan);
+                       if (ret < 0)
+                               goto out;
+                       if (ret == 1) {
+                               can_rename = false;
+                               *pending_move = 1;
+                       }
+               }
+
                /*
                 * link/move the ref to the new place. If we have an orphan
                 * inode, move it and update valid_path. If not, link or move
                 * it depending on the inode mode.
                 */
-               if (is_orphan) {
+               if (is_orphan && can_rename) {
                        ret = send_rename(sctx, valid_path, cur->full_path);
                        if (ret < 0)
                                goto out;
@@ -3503,7 +3644,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                        ret = fs_path_copy(valid_path, cur->full_path);
                        if (ret < 0)
                                goto out;
-               } else {
+               } else if (can_rename) {
                        if (S_ISDIR(sctx->cur_inode_mode)) {
                                /*
                                 * Dirs can't be linked, so move it. For moved
index a116b55ce7880a5e64837dfd6cd66f7412e27cec..054fc0d97131b239486a47a5b8ef4b3f120c2e6b 100644 (file)
@@ -911,6 +911,197 @@ out:
        return ret;
 }
 
+static int test_extent_accounting(void)
+{
+       struct inode *inode = NULL;
+       struct btrfs_root *root = NULL;
+       int ret = -ENOMEM;
+
+       inode = btrfs_new_test_inode();
+       if (!inode) {
+               test_msg("Couldn't allocate inode\n");
+               return ret;
+       }
+
+       root = btrfs_alloc_dummy_root();
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate root\n");
+               goto out;
+       }
+
+       root->fs_info = btrfs_alloc_dummy_fs_info();
+       if (!root->fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
+               goto out;
+       }
+
+       BTRFS_I(inode)->root = root;
+       btrfs_test_inode_set_ops(inode);
+
+       /* [BTRFS_MAX_EXTENT_SIZE] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, 0, BTRFS_MAX_EXTENT_SIZE - 1,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 1) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 1, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE][4k] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE,
+                                       BTRFS_MAX_EXTENT_SIZE + 4095, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE/2][4K HOLE][the rest] */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
+                              BTRFS_MAX_EXTENT_SIZE >> 1,
+                              (BTRFS_MAX_EXTENT_SIZE >> 1) + 4095,
+                              EXTENT_DELALLOC | EXTENT_DIRTY |
+                              EXTENT_UPTODATE | EXTENT_DO_ACCOUNTING, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE][4K] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE >> 1,
+                                       (BTRFS_MAX_EXTENT_SIZE >> 1) + 4095,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 2) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 2, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /*
+        * [BTRFS_MAX_EXTENT_SIZE+4K][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4K]
+        *
+        * I'm artificially adding 2 to outstanding_extents because in the
+        * buffered IO case we'd add things up as we go, but I don't feel like
+        * doing that here, this isn't the interesting case we want to test.
+        */
+       BTRFS_I(inode)->outstanding_extents += 2;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE + 8192,
+                                       (BTRFS_MAX_EXTENT_SIZE << 1) + 12287,
+                                       NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 4) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 4, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE+4k][4k][BTRFS_MAX_EXTENT_SIZE+4k] */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE+4096,
+                                       BTRFS_MAX_EXTENT_SIZE+8191, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 3) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 3, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* [BTRFS_MAX_EXTENT_SIZE+4k][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4k] */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
+                              BTRFS_MAX_EXTENT_SIZE+4096,
+                              BTRFS_MAX_EXTENT_SIZE+8191,
+                              EXTENT_DIRTY | EXTENT_DELALLOC |
+                              EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 4) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 4, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /*
+        * Refill the hole again just for good measure, because I thought it
+        * might fail and I'd rather satisfy my paranoia at this point.
+        */
+       BTRFS_I(inode)->outstanding_extents++;
+       ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE+4096,
+                                       BTRFS_MAX_EXTENT_SIZE+8191, NULL);
+       if (ret) {
+               test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents != 3) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 3, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+
+       /* Empty */
+       ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                              EXTENT_DIRTY | EXTENT_DELALLOC |
+                              EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                              NULL, GFP_NOFS);
+       if (ret) {
+               test_msg("clear_extent_bit returned %d\n", ret);
+               goto out;
+       }
+       if (BTRFS_I(inode)->outstanding_extents) {
+               ret = -EINVAL;
+               test_msg("Miscount, wanted 0, got %u\n",
+                        BTRFS_I(inode)->outstanding_extents);
+               goto out;
+       }
+       ret = 0;
+out:
+       if (ret)
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                                EXTENT_DIRTY | EXTENT_DELALLOC |
+                                EXTENT_DO_ACCOUNTING | EXTENT_UPTODATE, 0, 0,
+                                NULL, GFP_NOFS);
+       iput(inode);
+       btrfs_free_dummy_root(root);
+       return ret;
+}
+
 int btrfs_test_inodes(void)
 {
        int ret;
@@ -924,5 +1115,9 @@ int btrfs_test_inodes(void)
        if (ret)
                return ret;
        test_msg("Running hole first btrfs_get_extent test\n");
-       return test_hole_first();
+       ret = test_hole_first();
+       if (ret)
+               return ret;
+       test_msg("Running outstanding_extents tests\n");
+       return test_extent_accounting();
 }
index 7e80f32550a663e7438d3e5fb8b1c37fcc391b64..8be4278e25e8e06e32d52b5ac412201d7b20a53c 100644 (file)
@@ -1023,17 +1023,13 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
        u64 old_root_bytenr;
        u64 old_root_used;
        struct btrfs_root *tree_root = root->fs_info->tree_root;
-       bool extent_root = (root->objectid == BTRFS_EXTENT_TREE_OBJECTID);
 
        old_root_used = btrfs_root_used(&root->root_item);
-       btrfs_write_dirty_block_groups(trans, root);
 
        while (1) {
                old_root_bytenr = btrfs_root_bytenr(&root->root_item);
                if (old_root_bytenr == root->node->start &&
-                   old_root_used == btrfs_root_used(&root->root_item) &&
-                   (!extent_root ||
-                    list_empty(&trans->transaction->dirty_bgs)))
+                   old_root_used == btrfs_root_used(&root->root_item))
                        break;
 
                btrfs_set_root_node(&root->root_item, root->node);
@@ -1044,17 +1040,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                        return ret;
 
                old_root_used = btrfs_root_used(&root->root_item);
-               if (extent_root) {
-                       ret = btrfs_write_dirty_block_groups(trans, root);
-                       if (ret)
-                               return ret;
-               }
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               if (ret)
-                       return ret;
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               if (ret)
-                       return ret;
        }
 
        return 0;
@@ -1071,6 +1056,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                                         struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
+       struct list_head *dirty_bgs = &trans->transaction->dirty_bgs;
        struct list_head *next;
        struct extent_buffer *eb;
        int ret;
@@ -1098,11 +1084,15 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
        if (ret)
                return ret;
 
+       ret = btrfs_setup_space_cache(trans, root);
+       if (ret)
+               return ret;
+
        /* run_qgroups might have added some more refs */
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        if (ret)
                return ret;
-
+again:
        while (!list_empty(&fs_info->dirty_cowonly_roots)) {
                next = fs_info->dirty_cowonly_roots.next;
                list_del_init(next);
@@ -1115,8 +1105,23 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                ret = update_cowonly_root(trans, root);
                if (ret)
                        return ret;
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               if (ret)
+                       return ret;
        }
 
+       while (!list_empty(dirty_bgs)) {
+               ret = btrfs_write_dirty_block_groups(trans, root);
+               if (ret)
+                       return ret;
+               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+               if (ret)
+                       return ret;
+       }
+
+       if (!list_empty(&fs_info->dirty_cowonly_roots))
+               goto again;
+
        list_add_tail(&fs_info->extent_root->dirty_list,
                      &trans->transaction->switch_commits);
        btrfs_after_dev_replace_commit(fs_info);
@@ -1814,6 +1819,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                wait_for_commit(root, cur_trans);
 
+               if (unlikely(cur_trans->aborted))
+                       ret = cur_trans->aborted;
+
                btrfs_put_transaction(cur_trans);
 
                return ret;
index 9a37f8b39bae9058a20aafe11c59793409115005..c5b8ba37f88e31fa188258af9c6e13036c2df18f 100644 (file)
@@ -1012,7 +1012,7 @@ again:
                base = btrfs_item_ptr_offset(leaf, path->slots[0]);
 
                while (cur_offset < item_size) {
-                       extref = (struct btrfs_inode_extref *)base + cur_offset;
+                       extref = (struct btrfs_inode_extref *)(base + cur_offset);
 
                        victim_name_len = btrfs_inode_extref_name_len(leaf, extref);
 
index cd4d1315aaa92d43476a9e86c521e94a04519d0e..8222f6f74147972ba1b654c12b013c55a3b60825 100644 (file)
@@ -4903,10 +4903,17 @@ static void sort_parity_stripes(struct btrfs_bio *bbio, int num_stripes)
 static struct btrfs_bio *alloc_btrfs_bio(int total_stripes, int real_stripes)
 {
        struct btrfs_bio *bbio = kzalloc(
+                /* the size of the btrfs_bio */
                sizeof(struct btrfs_bio) +
+               /* plus the variable array for the stripes */
                sizeof(struct btrfs_bio_stripe) * (total_stripes) +
+               /* plus the variable array for the tgt dev */
                sizeof(int) * (real_stripes) +
-               sizeof(u64) * (real_stripes),
+               /*
+                * plus the raid_map, which includes both the tgt dev
+                * and the stripes
+                */
+               sizeof(u64) * (total_stripes),
                GFP_NOFS);
        if (!bbio)
                return NULL;
index 47b19465f0dc64e85d00d99eaee50e88de9f1014..883b93623bc5682ecde2684bfe936bb98fd9e51d 100644 (file)
@@ -111,6 +111,8 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
                                        name, name_len, -1);
                if (!di && (flags & XATTR_REPLACE))
                        ret = -ENODATA;
+               else if (IS_ERR(di))
+                       ret = PTR_ERR(di);
                else if (di)
                        ret = btrfs_delete_one_dir_name(trans, root, path, di);
                goto out;
@@ -127,10 +129,12 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
                ASSERT(mutex_is_locked(&inode->i_mutex));
                di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode),
                                        name, name_len, 0);
-               if (!di) {
+               if (!di)
                        ret = -ENODATA;
+               else if (IS_ERR(di))
+                       ret = PTR_ERR(di);
+               if (ret)
                        goto out;
-               }
                btrfs_release_path(path);
                di = NULL;
        }
index 4ac7445e6ec70516848e942f54a6846a8541113b..aa0dc2573374184597b9e449fad6467f924f0f45 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 d3aa999ab78520fcd4819f99548247e231df591b..480cf9c81d505b8351dd76eee0f012110c3f2b9c 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 a94b3e67318283dd54d61fc595ecb2037ba3a515..ca30c391a894a0e9df8eac6ed1ede194c89f1885 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 2d4f37235ed0fa360782ae237c89fccccbf8b719..3e126d7bb2ea5bec97c9d6e02973a49886261580 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 689f035915cf70f075d71fca5e281ec009c5420a..22dfdf17d06547f3d1b3abbc302bb03abf1b047b 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 96b5d40a2ece611b27ed19668cc4b7b665605113..eab05e1aa587424863d6914eb351da9fdcf17437 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 3417340bf89e677fe0c46bf98cf922dd39d29a3a..65cd7a84c8bc3206033a917fe9d98fc939cbe1af 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 90d1882b306face4c53d10ed08c44e3ec77b726a..5ba029e627cc22db0648317a619685e545977316 100644 (file)
@@ -124,7 +124,7 @@ ecryptfs_get_key_payload_data(struct key *key)
 }
 
 #define ECRYPTFS_MAX_KEYSET_SIZE 1024
-#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
+#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 31
 #define ECRYPTFS_MAX_NUM_ENC_KEYS 64
 #define ECRYPTFS_MAX_IV_BYTES 16       /* 128 bits */
 #define ECRYPTFS_SALT_BYTES 2
@@ -237,7 +237,7 @@ struct ecryptfs_crypt_stat {
        struct crypto_ablkcipher *tfm;
        struct crypto_hash *hash_tfm; /* Crypto context for generating
                                       * the initialization vectors */
-       unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+       unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
        unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
        unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
        struct list_head keysig_list;
index b07731e68c0b4d39cf75a5840033638cf37c123f..fd39bad6f1bdf8bbcb4321a8fc8ff1934d67167c 100644 (file)
@@ -303,9 +303,22 @@ ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct file *lower_file = ecryptfs_file_to_lower(file);
        long rc = -ENOTTY;
 
-       if (lower_file->f_op->unlocked_ioctl)
+       if (!lower_file->f_op->unlocked_ioctl)
+               return rc;
+
+       switch (cmd) {
+       case FITRIM:
+       case FS_IOC_GETFLAGS:
+       case FS_IOC_SETFLAGS:
+       case FS_IOC_GETVERSION:
+       case FS_IOC_SETVERSION:
                rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
-       return rc;
+               fsstack_copy_attr_all(file_inode(file), file_inode(lower_file));
+
+               return rc;
+       default:
+               return rc;
+       }
 }
 
 #ifdef CONFIG_COMPAT
@@ -315,9 +328,22 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct file *lower_file = ecryptfs_file_to_lower(file);
        long rc = -ENOIOCTLCMD;
 
-       if (lower_file->f_op->compat_ioctl)
+       if (!lower_file->f_op->compat_ioctl)
+               return rc;
+
+       switch (cmd) {
+       case FITRIM:
+       case FS_IOC32_GETFLAGS:
+       case FS_IOC32_SETFLAGS:
+       case FS_IOC32_GETVERSION:
+       case FS_IOC32_SETVERSION:
                rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
-       return rc;
+               fsstack_copy_attr_all(file_inode(file), file_inode(lower_file));
+
+               return rc;
+       default:
+               return rc;
+       }
 }
 #endif
 
index 917bd5c9776aabcff5b482f59bd8d316193ead35..6bd67e2011f083e4e184e4d2d336cb15176d40ee 100644 (file)
@@ -891,7 +891,7 @@ struct ecryptfs_parse_tag_70_packet_silly_stack {
        struct blkcipher_desc desc;
        char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
        char iv[ECRYPTFS_MAX_IV_BYTES];
-       char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+       char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
 };
 
 /**
index 1895d60f4122c21d0e2ee267066c6308473ba642..c095d32642599f90cf68a9437b9a10674d5cd3d9 100644 (file)
@@ -407,7 +407,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
        if (!cipher_name_set) {
                int cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
 
-               BUG_ON(cipher_name_len >= ECRYPTFS_MAX_CIPHER_NAME_SIZE);
+               BUG_ON(cipher_name_len > ECRYPTFS_MAX_CIPHER_NAME_SIZE);
                strcpy(mount_crypt_stat->global_default_cipher_name,
                       ECRYPTFS_DEFAULT_CIPHER);
        }
index e907052eeadb69f683df3c7d8838106c6e36905b..32a8bbd7a9ad1121f9b100da08f80500736bcebf 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 ed19a7d622fa35decaa08b10e83b8bdee8712419..39706c57ad3cb157d81594065a15f154f61d7bd8 100644 (file)
@@ -890,8 +890,8 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
 
        newpage = buf->page;
 
-       if (WARN_ON(!PageUptodate(newpage)))
-               return -EIO;
+       if (!PageUptodate(newpage))
+               SetPageUptodate(newpage);
 
        ClearPageMappedToDisk(newpage);
 
@@ -1353,6 +1353,17 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
        return err;
 }
 
+static int fuse_dev_open(struct inode *inode, struct file *file)
+{
+       /*
+        * The fuse device's file's private_data is used to hold
+        * the fuse_conn(ection) when it is mounted, and is used to
+        * keep track of whether the file has been mounted already.
+        */
+       file->private_data = NULL;
+       return 0;
+}
+
 static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
                              unsigned long nr_segs, loff_t pos)
 {
@@ -1797,6 +1808,9 @@ copy_finish:
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
                       unsigned int size, struct fuse_copy_state *cs)
 {
+       /* Don't try to move pages (yet) */
+       cs->move_pages = 0;
+
        switch (code) {
        case FUSE_NOTIFY_POLL:
                return fuse_notify_poll(fc, size, cs);
@@ -2217,6 +2231,7 @@ static int fuse_dev_fasync(int fd, struct file *file, int on)
 
 const struct file_operations fuse_dev_operations = {
        .owner          = THIS_MODULE,
+       .open           = fuse_dev_open,
        .llseek         = no_llseek,
        .read           = do_sync_read,
        .aio_read       = fuse_dev_read,
index 6e560d56094b2ccaf7091ec784a6a039af214f43..754fdf8c6356388f16bbdc285240394b350bd90e 100644 (file)
@@ -131,13 +131,16 @@ skip:
        hfs_bnode_write(node, entry, data_off + key_len, entry_len);
        hfs_bnode_dump(node);
 
-       if (new_node) {
-               /* update parent key if we inserted a key
-                * at the start of the first node
-                */
-               if (!rec && new_node != node)
-                       hfs_brec_update_parent(fd);
+       /*
+        * update parent key if we inserted a key
+        * at the start of the node and it is not the new node
+        */
+       if (!rec && new_node != node) {
+               hfs_bnode_read_key(node, fd->search_key, data_off + size);
+               hfs_brec_update_parent(fd);
+       }
 
+       if (new_node) {
                hfs_bnode_put(fd->bnode);
                if (!new_node->parent) {
                        hfs_btree_inc_height(tree);
@@ -168,9 +171,6 @@ skip:
                goto again;
        }
 
-       if (!rec)
-               hfs_brec_update_parent(fd);
-
        return 0;
 }
 
@@ -370,6 +370,8 @@ again:
        if (IS_ERR(parent))
                return PTR_ERR(parent);
        __hfs_brec_find(parent, fd, hfs_find_rec_by_key);
+       if (fd->record < 0)
+               return -ENOENT;
        hfs_bnode_dump(parent);
        rec = fd->record;
 
index b684e8a132e6255b7f294321ccd3a2f0e5097a09..2bacb99885665f3a0fae9579a569128195d86fd4 100644 (file)
@@ -207,6 +207,7 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
                goto out_free;
        }
 
+       of->event = atomic_read(&of->kn->attr.open->event);
        ops = kernfs_ops(of->kn);
        if (ops->read)
                len = ops->read(of, buf, len, *ppos);
index 365c82e1b3a9a602057e65edc9b857c6adce6b76..40bc384728c0e07b637dccfa755fe49b5751bf86 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 f9f4845db989e58b7e09f3e46b185f5ff5d2d9e4..19874151e95c9908660132e6a3e2e6d7d2d3c8e4 100644 (file)
@@ -433,7 +433,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
 
 static bool nfs_client_init_is_complete(const struct nfs_client *clp)
 {
-       return clp->cl_cons_state != NFS_CS_INITING;
+       return clp->cl_cons_state <= NFS_CS_READY;
 }
 
 int nfs_wait_client_init_complete(const struct nfs_client *clp)
index a1f0685b42ff7d2e42eed249e178ecdbbee7befc..a6ad688658803424d726afae85597ad2ace80044 100644 (file)
@@ -181,8 +181,8 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
                        clear_bit(NFS_DELEGATION_NEED_RECLAIM,
                                  &delegation->flags);
                        spin_unlock(&delegation->lock);
-                       put_rpccred(oldcred);
                        rcu_read_unlock();
+                       put_rpccred(oldcred);
                        trace_nfs4_reclaim_delegation(inode, res->delegation_type);
                } else {
                        /* We appear to have raced with a delegation return. */
@@ -370,7 +370,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
                        delegation = NULL;
                        goto out;
                }
-               freeme = nfs_detach_delegation_locked(nfsi, 
+               if (test_and_set_bit(NFS_DELEGATION_RETURNING,
+                                       &old_delegation->flags))
+                       goto out;
+               freeme = nfs_detach_delegation_locked(nfsi,
                                old_delegation, clp);
                if (freeme == NULL)
                        goto out;
@@ -433,6 +436,8 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
 {
        bool ret = false;
 
+       if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
+               goto out;
        if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
                ret = true;
        if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
@@ -444,6 +449,7 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
                        ret = true;
                spin_unlock(&delegation->lock);
        }
+out:
        return ret;
 }
 
@@ -471,14 +477,20 @@ restart:
                                                                super_list) {
                        if (!nfs_delegation_need_return(delegation))
                                continue;
-                       inode = nfs_delegation_grab_inode(delegation);
-                       if (inode == NULL)
+                       if (!nfs_sb_active(server->super))
                                continue;
+                       inode = nfs_delegation_grab_inode(delegation);
+                       if (inode == NULL) {
+                               rcu_read_unlock();
+                               nfs_sb_deactive(server->super);
+                               goto restart;
+                       }
                        delegation = nfs_start_delegation_return_locked(NFS_I(inode));
                        rcu_read_unlock();
 
                        err = nfs_end_delegation_return(inode, delegation, 0);
                        iput(inode);
+                       nfs_sb_deactive(server->super);
                        if (!err)
                                goto restart;
                        set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
@@ -809,19 +821,30 @@ restart:
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
                list_for_each_entry_rcu(delegation, &server->delegations,
                                                                super_list) {
+                       if (test_bit(NFS_DELEGATION_RETURNING,
+                                               &delegation->flags))
+                               continue;
                        if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
                                                &delegation->flags) == 0)
                                continue;
-                       inode = nfs_delegation_grab_inode(delegation);
-                       if (inode == NULL)
+                       if (!nfs_sb_active(server->super))
                                continue;
-                       delegation = nfs_detach_delegation(NFS_I(inode),
-                                       delegation, server);
+                       inode = nfs_delegation_grab_inode(delegation);
+                       if (inode == NULL) {
+                               rcu_read_unlock();
+                               nfs_sb_deactive(server->super);
+                               goto restart;
+                       }
+                       delegation = nfs_start_delegation_return_locked(NFS_I(inode));
                        rcu_read_unlock();
-
-                       if (delegation != NULL)
-                               nfs_free_delegation(delegation);
+                       if (delegation != NULL) {
+                               delegation = nfs_detach_delegation(NFS_I(inode),
+                                       delegation, server);
+                               if (delegation != NULL)
+                                       nfs_free_delegation(delegation);
+                       }
                        iput(inode);
+                       nfs_sb_deactive(server->super);
                        goto restart;
                }
        }
index 9b0c55cb2a2eaa9166670258ef7bf2b87824a0b7..c19e16f0b2d049f972acee413a287d9f73759ba3 100644 (file)
@@ -408,14 +408,22 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc,
        return 0;
 }
 
+/* Match file and dirent using either filehandle or fileid
+ * Note: caller is responsible for checking the fsid
+ */
 static
 int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
 {
+       struct nfs_inode *nfsi;
+
        if (dentry->d_inode == NULL)
                goto different;
-       if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0)
-               goto different;
-       return 1;
+
+       nfsi = NFS_I(dentry->d_inode);
+       if (entry->fattr->fileid == nfsi->fileid)
+               return 1;
+       if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0)
+               return 1;
 different:
        return 0;
 }
@@ -469,6 +477,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
        struct inode *inode;
        int status;
 
+       if (!(entry->fattr->valid & NFS_ATTR_FATTR_FILEID))
+               return;
+       if (!(entry->fattr->valid & NFS_ATTR_FATTR_FSID))
+               return;
        if (filename.name[0] == '.') {
                if (filename.len == 1)
                        return;
@@ -479,6 +491,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 
        dentry = d_lookup(parent, &filename);
        if (dentry != NULL) {
+               /* Is there a mountpoint here? If so, just exit */
+               if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
+                                       &entry->fattr->fsid))
+                       goto out;
                if (nfs_same_file(dentry, entry)) {
                        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                        status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
index 94712fc781fa58fa162c8399c6b9427aa242f5ce..e679d24c39d3a57d5ef510a22d5ccbe2832c5335 100644 (file)
@@ -178,7 +178,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
                iocb->ki_filp,
                iov_iter_count(to), (unsigned long) iocb->ki_pos);
 
-       result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
+       result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping);
        if (!result) {
                result = generic_file_read_iter(iocb, to);
                if (result > 0)
@@ -199,7 +199,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
        dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
                filp, (unsigned long) count, (unsigned long long) *ppos);
 
-       res = nfs_revalidate_mapping(inode, filp->f_mapping);
+       res = nfs_revalidate_mapping_protected(inode, filp->f_mapping);
        if (!res) {
                res = generic_file_splice_read(filp, ppos, pipe, count, flags);
                if (res > 0)
@@ -372,6 +372,10 @@ start:
                                 nfs_wait_bit_killable, TASK_KILLABLE);
        if (ret)
                return ret;
+       /*
+        * Wait for O_DIRECT to complete
+        */
+       nfs_inode_dio_wait(mapping->host);
 
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page)
@@ -619,6 +623,9 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        /* make sure the cache has finished storing the page */
        nfs_fscache_wait_on_page_write(NFS_I(inode), page);
 
+       wait_on_bit_action(&NFS_I(inode)->flags, NFS_INO_INVALIDATING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+
        lock_page(page);
        mapping = page_file_mapping(page);
        if (mapping != inode->i_mapping)
index 83107be3dd0109ab54c5f2b0c72fa59c64dd8d57..d42dff6d5e983f65c2e2f299e12d5353f54236c7 100644 (file)
@@ -556,6 +556,7 @@ EXPORT_SYMBOL_GPL(nfs_setattr);
  * This is a copy of the common vmtruncate, but with the locking
  * corrected to take into account the fact that NFS requires
  * inode->i_size to be updated under the inode->i_lock.
+ * Note: must be called with inode->i_lock held!
  */
 static int nfs_vmtruncate(struct inode * inode, loff_t offset)
 {
@@ -565,14 +566,14 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
        if (err)
                goto out;
 
-       spin_lock(&inode->i_lock);
        i_size_write(inode, offset);
        /* Optimisation */
        if (offset == 0)
                NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
-       spin_unlock(&inode->i_lock);
 
+       spin_unlock(&inode->i_lock);
        truncate_pagecache(inode, offset);
+       spin_lock(&inode->i_lock);
 out:
        return err;
 }
@@ -585,10 +586,15 @@ out:
  * Note: we do this in the *proc.c in order to ensure that
  *       it works for things like exclusive creates too.
  */
-void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
+void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
+               struct nfs_fattr *fattr)
 {
+       /* Barrier: bump the attribute generation count. */
+       nfs_fattr_set_barrier(fattr);
+
+       spin_lock(&inode->i_lock);
+       NFS_I(inode)->attr_gencount = fattr->gencount;
        if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
-               spin_lock(&inode->i_lock);
                if ((attr->ia_valid & ATTR_MODE) != 0) {
                        int mode = attr->ia_mode & S_IALLUGO;
                        mode |= inode->i_mode & ~S_IALLUGO;
@@ -600,12 +606,13 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
                        inode->i_gid = attr->ia_gid;
                nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS
                                | NFS_INO_INVALID_ACL);
-               spin_unlock(&inode->i_lock);
        }
        if ((attr->ia_valid & ATTR_SIZE) != 0) {
                nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
                nfs_vmtruncate(inode, attr->ia_size);
        }
+       nfs_update_inode(inode, fattr);
+       spin_unlock(&inode->i_lock);
 }
 EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
 
@@ -1028,6 +1035,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
 
        if (mapping->nrpages != 0) {
                if (S_ISREG(inode->i_mode)) {
+                       unmap_mapping_range(mapping, 0, 0, 0);
                        ret = nfs_sync_mapping(mapping);
                        if (ret < 0)
                                return ret;
@@ -1060,11 +1068,14 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
 }
 
 /**
- * nfs_revalidate_mapping - Revalidate the pagecache
+ * __nfs_revalidate_mapping - Revalidate the pagecache
  * @inode - pointer to host inode
  * @mapping - pointer to mapping
+ * @may_lock - take inode->i_mutex?
  */
-int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+static int __nfs_revalidate_mapping(struct inode *inode,
+               struct address_space *mapping,
+               bool may_lock)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        unsigned long *bitlock = &nfsi->flags;
@@ -1113,7 +1124,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
        nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
        spin_unlock(&inode->i_lock);
        trace_nfs_invalidate_mapping_enter(inode);
-       ret = nfs_invalidate_mapping(inode, mapping);
+       if (may_lock) {
+               mutex_lock(&inode->i_mutex);
+               ret = nfs_invalidate_mapping(inode, mapping);
+               mutex_unlock(&inode->i_mutex);
+       } else
+               ret = nfs_invalidate_mapping(inode, mapping);
        trace_nfs_invalidate_mapping_exit(inode, ret);
 
        clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
@@ -1123,6 +1139,29 @@ out:
        return ret;
 }
 
+/**
+ * nfs_revalidate_mapping - Revalidate the pagecache
+ * @inode - pointer to host inode
+ * @mapping - pointer to mapping
+ */
+int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+{
+       return __nfs_revalidate_mapping(inode, mapping, false);
+}
+
+/**
+ * nfs_revalidate_mapping_protected - Revalidate the pagecache
+ * @inode - pointer to host inode
+ * @mapping - pointer to mapping
+ *
+ * Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex
+ * while invalidating the mapping.
+ */
+int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping)
+{
+       return __nfs_revalidate_mapping(inode, mapping, true);
+}
+
 static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -1231,13 +1270,6 @@ static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fat
        return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
 }
 
-static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
-{
-       if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
-               return 0;
-       return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
-}
-
 static atomic_long_t nfs_attr_generation_counter;
 
 static unsigned long nfs_read_attr_generation_counter(void)
@@ -1249,6 +1281,7 @@ unsigned long nfs_inc_attr_generation_counter(void)
 {
        return atomic_long_inc_return(&nfs_attr_generation_counter);
 }
+EXPORT_SYMBOL_GPL(nfs_inc_attr_generation_counter);
 
 void nfs_fattr_init(struct nfs_fattr *fattr)
 {
@@ -1260,6 +1293,22 @@ void nfs_fattr_init(struct nfs_fattr *fattr)
 }
 EXPORT_SYMBOL_GPL(nfs_fattr_init);
 
+/**
+ * nfs_fattr_set_barrier
+ * @fattr: attributes
+ *
+ * Used to set a barrier after an attribute was updated. This
+ * barrier ensures that older attributes from RPC calls that may
+ * have raced with our update cannot clobber these new values.
+ * Note that you are still responsible for ensuring that other
+ * operations which change the attribute on the server do not
+ * collide.
+ */
+void nfs_fattr_set_barrier(struct nfs_fattr *fattr)
+{
+       fattr->gencount = nfs_inc_attr_generation_counter();
+}
+
 struct nfs_fattr *nfs_alloc_fattr(void)
 {
        struct nfs_fattr *fattr;
@@ -1370,7 +1419,6 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
 
        return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 ||
                nfs_ctime_need_update(inode, fattr) ||
-               nfs_size_need_update(inode, fattr) ||
                ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
 }
 
@@ -1460,6 +1508,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        int status;
 
        spin_lock(&inode->i_lock);
+       nfs_fattr_set_barrier(fattr);
        status = nfs_post_op_update_inode_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
 
@@ -1468,7 +1517,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
 
 /**
- * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache
  * @inode - pointer to inode
  * @fattr - updated attributes
  *
@@ -1478,11 +1527,10 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
  *
  * This function is mainly designed to be used by the ->write_done() functions.
  */
-int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr)
 {
        int status;
 
-       spin_lock(&inode->i_lock);
        /* Don't do a WCC update if these attributes are already stale */
        if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
                        !nfs_inode_attrs_need_update(inode, fattr)) {
@@ -1514,6 +1562,27 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
        }
 out_noforce:
        status = nfs_post_op_update_inode_locked(inode, fattr);
+       return status;
+}
+
+/**
+ * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * @inode - pointer to inode
+ * @fattr - updated attributes
+ *
+ * After an operation that has changed the inode metadata, mark the
+ * attribute cache as being invalid, then try to update it. Fake up
+ * weak cache consistency data, if none exist.
+ *
+ * This function is mainly designed to be used by the ->write_done() functions.
+ */
+int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+{
+       int status;
+
+       spin_lock(&inode->i_lock);
+       nfs_fattr_set_barrier(fattr);
+       status = nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
        return status;
 }
@@ -1715,6 +1784,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
+               /* Set barrier to be more recent than all outstanding updates */
                nfsi->attr_gencount = nfs_inc_attr_generation_counter();
        } else {
                if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
@@ -1722,6 +1792,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                                nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
                        nfsi->attrtimeo_timestamp = now;
                }
+               /* Set the barrier to be more recent than this fattr */
+               if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
+                       nfsi->attr_gencount = fattr->gencount;
        }
        invalid &= ~NFS_INO_INVALID_ATTR;
        /* Don't invalidate the data if we were to blame */
index b802fb3a2d99ffd76a57aecc6ce6739ca104e515..9e6475bc5ba22be7293c687d78dda1a626d3024b 100644 (file)
@@ -459,6 +459,7 @@ void nfs_mark_request_commit(struct nfs_page *req,
                             struct nfs_commit_info *cinfo,
                             u32 ds_commit_idx);
 int nfs_write_need_commit(struct nfs_pgio_header *);
+void nfs_writeback_update_inode(struct nfs_pgio_header *hdr);
 int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
                            int how, struct nfs_commit_info *cinfo);
 void nfs_retry_commit(struct list_head *page_list,
index 78e557c3ab87d014694e6e4098faefb20553f579..1f11d2533ee4107bd9ae3f8de460b38ecdbaae74 100644 (file)
@@ -138,7 +138,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        nfs_fattr_init(fattr);
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
        if (status == 0)
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
        dprintk("NFS reply setattr: %d\n", status);
        return status;
 }
@@ -834,7 +834,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
        if (nfs3_async_handle_jukebox(task, inode))
                return -EAGAIN;
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr);
+               nfs_writeback_update_inode(hdr);
        return 0;
 }
 
index 2a932fdc57cb37b2676e08dcb33838c9aecd2a9a..53852a4bd88be68781bb9dd8a39760fd497d1d61 100644 (file)
@@ -1987,6 +1987,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
                        entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
 
+               if (entry->fattr->fileid != entry->ino) {
+                       entry->fattr->mounted_on_fileid = entry->ino;
+                       entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
+               }
+
                /* In fact, a post_op_fh3: */
                p = xdr_inline_decode(xdr, 4);
                if (unlikely(p == NULL))
index 8646af9b11d2e1b866f1c1e789a5b6001a36c882..86d6214ea022fee66f16f976a17451590edde7b8 100644 (file)
@@ -621,6 +621,9 @@ int nfs41_walk_client_list(struct nfs_client *new,
        spin_lock(&nn->nfs_client_lock);
        list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
 
+               if (pos == new)
+                       goto found;
+
                if (pos->rpc_ops != new->rpc_ops)
                        continue;
 
@@ -639,10 +642,6 @@ int nfs41_walk_client_list(struct nfs_client *new,
                        prev = pos;
 
                        status = nfs_wait_client_init_complete(pos);
-                       if (pos->cl_cons_state == NFS_CS_SESSION_INITING) {
-                               nfs4_schedule_lease_recovery(pos);
-                               status = nfs4_wait_clnt_recover(pos);
-                       }
                        spin_lock(&nn->nfs_client_lock);
                        if (status < 0)
                                break;
@@ -668,7 +667,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
                 */
                if (!nfs4_match_client_owner_id(pos, new))
                        continue;
-
+found:
                atomic_inc(&pos->cl_count);
                *result = pos;
                status = 0;
index 88180ac5ea0eebdf34aa333130e69d7a7b49c38e..627f37c44456752d6bd90a8882ae373ec6d70718 100644 (file)
@@ -901,6 +901,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
        if (!cinfo->atomic || cinfo->before != dir->i_version)
                nfs_force_lookup_revalidate(dir);
        dir->i_version = cinfo->after;
+       nfsi->attr_gencount = nfs_inc_attr_generation_counter();
        nfs_fscache_invalidate(dir);
        spin_unlock(&dir->i_lock);
 }
@@ -1552,6 +1553,9 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod
 
        opendata->o_arg.open_flags = 0;
        opendata->o_arg.fmode = fmode;
+       opendata->o_arg.share_access = nfs4_map_atomic_open_share(
+                       NFS_SB(opendata->dentry->d_sb),
+                       fmode, 0);
        memset(&opendata->o_res, 0, sizeof(opendata->o_res));
        memset(&opendata->c_res, 0, sizeof(opendata->c_res));
        nfs4_init_opendata_res(opendata);
@@ -2413,8 +2417,8 @@ static int _nfs4_do_open(struct inode *dir,
                                opendata->o_res.f_attr, sattr,
                                state, label, olabel);
                if (status == 0) {
-                       nfs_setattr_update_inode(state->inode, sattr);
-                       nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
+                       nfs_setattr_update_inode(state->inode, sattr,
+                                       opendata->o_res.f_attr);
                        nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
                }
        }
@@ -2651,7 +2655,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                case -NFS4ERR_BAD_STATEID:
                case -NFS4ERR_EXPIRED:
                        if (!nfs4_stateid_match(&calldata->arg.stateid,
-                                               &state->stateid)) {
+                                               &state->open_stateid)) {
                                rpc_restart_call_prepare(task);
                                goto out_release;
                        }
@@ -2687,7 +2691,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
        is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
        is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
-       nfs4_stateid_copy(&calldata->arg.stateid, &state->stateid);
+       nfs4_stateid_copy(&calldata->arg.stateid, &state->open_stateid);
        /* Calculate the change in open mode */
        calldata->arg.fmode = 0;
        if (state->n_rdwr == 0) {
@@ -3288,7 +3292,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 
        status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label);
        if (status == 0) {
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
                nfs_setsecurity(inode, fattr, label);
        }
        nfs4_label_free(label);
@@ -4234,7 +4238,7 @@ static int nfs4_write_done_cb(struct rpc_task *task,
        }
        if (task->tk_status >= 0) {
                renew_lease(NFS_SERVER(inode), hdr->timestamp);
-               nfs_post_op_update_inode_force_wcc(inode, &hdr->fattr);
+               nfs_writeback_update_inode(hdr);
        }
        return 0;
 }
@@ -6893,9 +6897,13 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
 
        if (status == 0) {
                clp->cl_clientid = res.clientid;
-               clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
-               if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R))
+               clp->cl_exchange_flags = res.flags;
+               /* Client ID is not confirmed */
+               if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
+                       clear_bit(NFS4_SESSION_ESTABLISHED,
+                                       &clp->cl_session->session_state);
                        clp->cl_seqid = res.seqid;
+               }
 
                kfree(clp->cl_serverowner);
                clp->cl_serverowner = res.server_owner;
@@ -7227,6 +7235,9 @@ static void nfs4_update_session(struct nfs4_session *session,
                struct nfs41_create_session_res *res)
 {
        nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
+       /* Mark client id and session as being confirmed */
+       session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
+       set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state);
        session->flags = res->flags;
        memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
        if (res->flags & SESSION4_BACK_CHAN)
@@ -7322,8 +7333,8 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
        dprintk("--> nfs4_proc_destroy_session\n");
 
        /* session is still being setup */
-       if (session->clp->cl_cons_state != NFS_CS_READY)
-               return status;
+       if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state))
+               return 0;
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        trace_nfs4_destroy_session(session->clp, status);
index fc46c745589863425bff271942b76f7812db5aea..e3ea2c5324d68e92591058e896bf478538302a5a 100644 (file)
@@ -70,6 +70,7 @@ struct nfs4_session {
 
 enum nfs4_session_state {
        NFS4_SESSION_INITING,
+       NFS4_SESSION_ESTABLISHED,
 };
 
 extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
index 5ad908e9ce9c332696ed52a85a5c4324a45d8b02..f95e3b58bbc304ae381df2a5f1721d8074789c51 100644 (file)
@@ -346,9 +346,23 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
        status = nfs4_proc_exchange_id(clp, cred);
        if (status != NFS4_OK)
                return status;
-       set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
 
-       return nfs41_walk_client_list(clp, result, cred);
+       status = nfs41_walk_client_list(clp, result, cred);
+       if (status < 0)
+               return status;
+       if (clp != *result)
+               return 0;
+
+       /* Purge state if the client id was established in a prior instance */
+       if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R)
+               set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
+       else
+               set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+       nfs4_schedule_state_manager(clp);
+       status = nfs_wait_client_init_complete(clp);
+       if (status < 0)
+               nfs_put_client(clp);
+       return status;
 }
 
 #endif /* CONFIG_NFS_V4_1 */
index b09cc23d6f433bc5ea8aff6cfe68c3910c4f8319..c63189acd0523cf733ab494dc85c1acf0cdb8f33 100644 (file)
@@ -139,7 +139,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        nfs_fattr_init(fattr);
        status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
        if (status == 0)
-               nfs_setattr_update_inode(inode, sattr);
+               nfs_setattr_update_inode(inode, sattr, fattr);
        dprintk("NFS reply setattr: %d\n", status);
        return status;
 }
@@ -609,10 +609,8 @@ static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task,
 
 static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
 {
-       struct inode *inode = hdr->inode;
-
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr);
+               nfs_writeback_update_inode(hdr);
        return 0;
 }
 
index 595d81e354d18950a21615862b134ca8993f4c6e..849ed784d6ac1fc6b923c32278e089f87575b8db 100644 (file)
@@ -1377,6 +1377,36 @@ static int nfs_should_remove_suid(const struct inode *inode)
        return 0;
 }
 
+static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
+               struct nfs_fattr *fattr)
+{
+       struct nfs_pgio_args *argp = &hdr->args;
+       struct nfs_pgio_res *resp = &hdr->res;
+
+       if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
+               return;
+       if (argp->offset + resp->count != fattr->size)
+               return;
+       if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode))
+               return;
+       /* Set attribute barrier */
+       nfs_fattr_set_barrier(fattr);
+}
+
+void nfs_writeback_update_inode(struct nfs_pgio_header *hdr)
+{
+       struct nfs_fattr *fattr = hdr->res.fattr;
+       struct inode *inode = hdr->inode;
+
+       if (fattr == NULL)
+               return;
+       spin_lock(&inode->i_lock);
+       nfs_writeback_check_extend(hdr, fattr);
+       nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
+       spin_unlock(&inode->i_lock);
+}
+EXPORT_SYMBOL_GPL(nfs_writeback_update_inode);
+
 /*
  * This function is called when the WRITE call is complete.
  */
index cdbc78c7254218c80213877e90c08ec107aea223..03d647bf195d78bb3d6611553c9ad3e6fa4385a2 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 9da89fddab338fcebbeb51fc0ec71534e0defc5a..9aa2796da90d9169488a625d5f80e90010971ff4 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 3c1bfa15557116d0e78c87b191a5842bdeca9417..6904213a436368e47628af85701a3beb68e0550b 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 d30bea8d0277ab3bfa45e7d66c38ed410026f585..92b9d97aff4f1adfe24ed607d11661196a500ffc 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 f6b2a09f793f453e5b6c40e80ceb383a12af7616..8ba1d888f1e624d672453bd1eea20c40e054f746 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 df5e66caf100ca303005018932ccc8edadab4089..5fb7e78169a6b27a1a5a4d5e9ec354c9e32f6c43 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 83a9694ec485b0593e3de847464243640fcd7186..46ec934f5dee8c529020558bed4cd820956734f1 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 b2e3ff34762070a4b37085c051223809b59e4a6c..ecdbae19a766d914e7d68c005c14356455dc83af 100644 (file)
@@ -31,6 +31,8 @@
 #include "alloc.h"
 #include "dat.h"
 
+static void __nilfs_btree_init(struct nilfs_bmap *bmap);
+
 static struct nilfs_btree_path *nilfs_btree_alloc_path(void)
 {
        struct nilfs_btree_path *path;
@@ -368,6 +370,34 @@ static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
        return ret;
 }
 
+/**
+ * nilfs_btree_root_broken - verify consistency of btree root node
+ * @node: btree root node to be examined
+ * @ino: inode number
+ *
+ * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
+ */
+static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
+                                  unsigned long ino)
+{
+       int level, flags, nchildren;
+       int ret = 0;
+
+       level = nilfs_btree_node_get_level(node);
+       flags = nilfs_btree_node_get_flags(node);
+       nchildren = nilfs_btree_node_get_nchildren(node);
+
+       if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
+                    level > NILFS_BTREE_LEVEL_MAX ||
+                    nchildren < 0 ||
+                    nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
+               pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
+                       ino, level, flags, nchildren);
+               ret = 1;
+       }
+       return ret;
+}
+
 int nilfs_btree_broken_node_block(struct buffer_head *bh)
 {
        int ret;
@@ -1713,7 +1743,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *btree,
 
        /* convert and insert */
        dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL;
-       nilfs_btree_init(btree);
+       __nilfs_btree_init(btree);
        if (nreq != NULL) {
                nilfs_bmap_commit_alloc_ptr(btree, dreq, dat);
                nilfs_bmap_commit_alloc_ptr(btree, nreq, dat);
@@ -2294,12 +2324,23 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = {
        .bop_gather_data        =       NULL,
 };
 
-int nilfs_btree_init(struct nilfs_bmap *bmap)
+static void __nilfs_btree_init(struct nilfs_bmap *bmap)
 {
        bmap->b_ops = &nilfs_btree_ops;
        bmap->b_nchildren_per_block =
                NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(bmap));
-       return 0;
+}
+
+int nilfs_btree_init(struct nilfs_bmap *bmap)
+{
+       int ret = 0;
+
+       __nilfs_btree_init(bmap);
+
+       if (nilfs_btree_root_broken(nilfs_btree_get_root(bmap),
+                                   bmap->b_inode->i_ino))
+               ret = -EIO;
+       return ret;
 }
 
 void nilfs_btree_init_gc(struct nilfs_bmap *bmap)
index 469086b9f99bc8e20053e492237d48a3373bdb37..0c3f303baf32f196af9360f8f78773f29a31e139 100644 (file)
@@ -1907,6 +1907,7 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
                                             struct the_nilfs *nilfs)
 {
        struct nilfs_inode_info *ii, *n;
+       int during_mount = !(sci->sc_super->s_flags & MS_ACTIVE);
        int defer_iput = false;
 
        spin_lock(&nilfs->ns_inode_lock);
@@ -1919,10 +1920,10 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
                brelse(ii->i_bh);
                ii->i_bh = NULL;
                list_del_init(&ii->i_dirty);
-               if (!ii->vfs_inode.i_nlink) {
+               if (!ii->vfs_inode.i_nlink || during_mount) {
                        /*
-                        * Defer calling iput() to avoid a deadlock
-                        * over I_SYNC flag for inodes with i_nlink == 0
+                        * Defer calling iput() to avoid deadlocks if
+                        * i_nlink == 0 or mount is not yet finished.
                         */
                        list_add_tail(&ii->i_dirty, &sci->sc_iput_queue);
                        defer_iput = true;
index 9a66ff79ff2781d1c7992dbd3d4ec42a82008f59..d2f97ecca6a5dfe6091d56da09871449574524bf 100644 (file)
@@ -143,7 +143,8 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
            !(marks_mask & FS_ISDIR & ~marks_ignored_mask))
                return false;
 
-       if (event_mask & marks_mask & ~marks_ignored_mask)
+       if (event_mask & FAN_ALL_OUTGOING_EVENTS & marks_mask &
+                                ~marks_ignored_mask)
                return true;
 
        return false;
index 8490c64d34fef4fd0421c4bb7e7c7ea9f6d87bca..460c6c37e683f844bd9612d51e6b89224cabb22b 100644 (file)
@@ -502,7 +502,7 @@ static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super *osb)
 
 static inline int ocfs2_supports_append_dio(struct ocfs2_super *osb)
 {
-       if (osb->s_feature_ro_compat & OCFS2_FEATURE_RO_COMPAT_APPEND_DIO)
+       if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_APPEND_DIO)
                return 1;
        return 0;
 }
index 20e37a3ed26f3eb721ad45c2699a6332a098cee8..db64ce2d4667be86ca27aecc304c1125667906f6 100644 (file)
                                         | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \
                                         | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE \
                                         | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG  \
-                                        | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO)
+                                        | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO \
+                                        | OCFS2_FEATURE_INCOMPAT_APPEND_DIO)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP   (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
                                         | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
-                                        | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA \
-                                        | OCFS2_FEATURE_RO_COMPAT_APPEND_DIO)
+                                        | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
 
 /*
  * Heartbeat-only devices are missing journals and other files.  The
  */
 #define OCFS2_FEATURE_INCOMPAT_CLUSTERINFO     0x4000
 
+/*
+ * Append Direct IO support
+ */
+#define OCFS2_FEATURE_INCOMPAT_APPEND_DIO      0x8000
+
 /*
  * backup superblock flag is used to indicate that this volume
  * has backup superblocks.
 #define OCFS2_FEATURE_RO_COMPAT_USRQUOTA       0x0002
 #define OCFS2_FEATURE_RO_COMPAT_GRPQUOTA       0x0004
 
-/*
- * Append Direct IO support
- */
-#define OCFS2_FEATURE_RO_COMPAT_APPEND_DIO     0x0008
 
 /* The byte offset of the first backup block will be 1G.
  * The following will be 4G, 16G, 64G, 256G and 1T.
index b90952f528b1cdf7414e49b5613e439d6b89fb7a..5f0d1993e6e3952bda9352d231e8fce7dee838e8 100644 (file)
@@ -529,8 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data)
 {
        struct ovl_fs *ufs = sb->s_fs_info;
 
-       if (!(*flags & MS_RDONLY) &&
-           (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)))
+       if (!(*flags & MS_RDONLY) && !ufs->upper_mnt)
                return -EROFS;
 
        return 0;
@@ -615,9 +614,19 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
                        break;
 
                default:
+                       pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p);
                        return -EINVAL;
                }
        }
+
+       /* Workdir is useless in non-upper mount */
+       if (!config->upperdir && config->workdir) {
+               pr_info("overlayfs: option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
+                       config->workdir);
+               kfree(config->workdir);
+               config->workdir = NULL;
+       }
+
        return 0;
 }
 
@@ -837,7 +846,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_stack_depth = 0;
        if (ufs->config.upperdir) {
-               /* FIXME: workdir is not needed for a R/O mount */
                if (!ufs->config.workdir) {
                        pr_err("overlayfs: missing 'workdir'\n");
                        goto out_free_config;
@@ -847,6 +855,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                if (err)
                        goto out_free_config;
 
+               /* Upper fs should not be r/o */
+               if (upperpath.mnt->mnt_sb->s_flags & MS_RDONLY) {
+                       pr_err("overlayfs: upper fs is r/o, try multi-lower layers mount\n");
+                       err = -EINVAL;
+                       goto out_put_upperpath;
+               }
+
                err = ovl_mount_dir(ufs->config.workdir, &workpath);
                if (err)
                        goto out_put_upperpath;
@@ -869,8 +884,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        err = -EINVAL;
        stacklen = ovl_split_lowerdirs(lowertmp);
-       if (stacklen > OVL_MAX_STACK)
+       if (stacklen > OVL_MAX_STACK) {
+               pr_err("overlayfs: too many lower directries, limit is %d\n",
+                      OVL_MAX_STACK);
                goto out_free_lowertmp;
+       } else if (!ufs->config.upperdir && stacklen == 1) {
+               pr_err("overlayfs: at least 2 lowerdir are needed while upperdir nonexistent\n");
+               goto out_free_lowertmp;
+       }
 
        stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL);
        if (!stack)
@@ -932,8 +953,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                ufs->numlower++;
        }
 
-       /* If the upper fs is r/o or nonexistent, we mark overlayfs r/o too */
-       if (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY))
+       /* If the upper fs is nonexistent, we mark overlayfs r/o too */
+       if (!ufs->upper_mnt)
                sb->s_flags |= MS_RDONLY;
 
        sb->s_d_op = &ovl_dentry_operations;
index 956b75d61809f06cdf433411456bb08278726eb5..6dee68d013ffa69f1f6c9d49873f17f19eb3874d 100644 (file)
@@ -1325,6 +1325,9 @@ out:
 
 static int pagemap_open(struct inode *inode, struct file *file)
 {
+       /* do not disclose physical addresses: attack vector */
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
        pr_warn_once("Bits 55-60 of /proc/PID/pagemap entries are about "
                        "to stop being page-shift some time soon. See the "
                        "linux/Documentation/vm/pagemap.txt for details.\n");
index ce615d12fb44cfae0d6bf344cbf0b3d2e4f43e1d..a2e1cb8a568bf9d45e32c43539a2e6f8b56d83f4 100644 (file)
@@ -397,7 +397,8 @@ STATIC int                          /* error (positive) */
 xfs_zero_last_block(
        struct xfs_inode        *ip,
        xfs_fsize_t             offset,
-       xfs_fsize_t             isize)
+       xfs_fsize_t             isize,
+       bool                    *did_zeroing)
 {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_fileoff_t           last_fsb = XFS_B_TO_FSBT(mp, isize);
@@ -425,6 +426,7 @@ xfs_zero_last_block(
        zero_len = mp->m_sb.sb_blocksize - zero_offset;
        if (isize + zero_len > offset)
                zero_len = offset - isize;
+       *did_zeroing = true;
        return xfs_iozero(ip, isize, zero_len);
 }
 
@@ -443,7 +445,8 @@ int                                 /* error (positive) */
 xfs_zero_eof(
        struct xfs_inode        *ip,
        xfs_off_t               offset,         /* starting I/O offset */
-       xfs_fsize_t             isize)          /* current inode size */
+       xfs_fsize_t             isize,          /* current inode size */
+       bool                    *did_zeroing)
 {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_fileoff_t           start_zero_fsb;
@@ -465,7 +468,7 @@ xfs_zero_eof(
         * We only zero a part of that block so it is handled specially.
         */
        if (XFS_B_FSB_OFFSET(mp, isize) != 0) {
-               error = xfs_zero_last_block(ip, offset, isize);
+               error = xfs_zero_last_block(ip, offset, isize, did_zeroing);
                if (error)
                        return error;
        }
@@ -525,6 +528,7 @@ xfs_zero_eof(
                if (error)
                        return error;
 
+               *did_zeroing = true;
                start_zero_fsb = imap.br_startoff + imap.br_blockcount;
                ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
        }
@@ -567,13 +571,15 @@ restart:
         * having to redo all checks before.
         */
        if (*pos > i_size_read(inode)) {
+               bool    zero = false;
+
                if (*iolock == XFS_IOLOCK_SHARED) {
                        xfs_rw_iunlock(ip, *iolock);
                        *iolock = XFS_IOLOCK_EXCL;
                        xfs_rw_ilock(ip, *iolock);
                        goto restart;
                }
-               error = xfs_zero_eof(ip, *pos, i_size_read(inode));
+               error = xfs_zero_eof(ip, *pos, i_size_read(inode), &zero);
                if (error)
                        return error;
        }
index daafa1f6d2607722b338c8b5da458a979558d9b3..6163767aa8562f6d611a1442ed4f299aa85bceea 100644 (file)
@@ -2867,6 +2867,10 @@ xfs_rename(
         * Handle RENAME_EXCHANGE flags
         */
        if (flags & RENAME_EXCHANGE) {
+               if (target_ip == NULL) {
+                       error = -EINVAL;
+                       goto error_return;
+               }
                error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
                                         target_dp, target_name, target_ip,
                                         &free_list, &first_block, spaceres);
index 86cd6b39bed7be1dc4bd72be82e9a40b9c8b9825..a1cd55f3f351e1361e2a3ea790f88f5f5070e7e3 100644 (file)
@@ -384,10 +384,11 @@ enum xfs_prealloc_flags {
        XFS_PREALLOC_INVISIBLE  = (1 << 4),
 };
 
-int            xfs_update_prealloc_flags(struct xfs_inode *,
-                       enum xfs_prealloc_flags);
-int            xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
-int            xfs_iozero(struct xfs_inode *, loff_t, size_t);
+int    xfs_update_prealloc_flags(struct xfs_inode *ip,
+                                 enum xfs_prealloc_flags flags);
+int    xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
+                    xfs_fsize_t isize, bool *did_zeroing);
+int    xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);
 
 
 #define IHOLD(ip) \
index d919ad7b16bf9acbe01c6531a9254b372426911a..e53a903314225c030c45f694b4ffdaa509fa1ce8 100644 (file)
@@ -751,6 +751,7 @@ xfs_setattr_size(
        int                     error;
        uint                    lock_flags = 0;
        uint                    commit_flags = 0;
+       bool                    did_zeroing = false;
 
        trace_xfs_setattr(ip);
 
@@ -794,20 +795,16 @@ xfs_setattr_size(
                return error;
 
        /*
-        * Now we can make the changes.  Before we join the inode to the
-        * transaction, take care of the part of the truncation that must be
-        * done without the inode lock.  This needs to be done before joining
-        * the inode to the transaction, because the inode cannot be unlocked
-        * once it is a part of the transaction.
+        * File data changes must be complete before we start the transaction to
+        * modify the inode.  This needs to be done before joining the inode to
+        * the transaction because the inode cannot be unlocked once it is a
+        * part of the transaction.
+        *
+        * Start with zeroing any data block beyond EOF that we may expose on
+        * file extension.
         */
        if (newsize > oldsize) {
-               /*
-                * Do the first part of growing a file: zero any data in the
-                * last block that is beyond the old EOF.  We need to do this
-                * before the inode is joined to the transaction to modify
-                * i_size.
-                */
-               error = xfs_zero_eof(ip, newsize, oldsize);
+               error = xfs_zero_eof(ip, newsize, oldsize, &did_zeroing);
                if (error)
                        return error;
        }
@@ -817,23 +814,18 @@ xfs_setattr_size(
         * any previous writes that are beyond the on disk EOF and the new
         * EOF that have not been written out need to be written here.  If we
         * do not write the data out, we expose ourselves to the null files
-        * problem.
-        *
-        * Only flush from the on disk size to the smaller of the in memory
-        * file size or the new size as that's the range we really care about
-        * here and prevents waiting for other data not within the range we
-        * care about here.
+        * problem. Note that this includes any block zeroing we did above;
+        * otherwise those blocks may not be zeroed after a crash.
         */
-       if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) {
+       if (newsize > ip->i_d.di_size &&
+           (oldsize != ip->i_d.di_size || did_zeroing)) {
                error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
                                                      ip->i_d.di_size, newsize);
                if (error)
                        return error;
        }
 
-       /*
-        * Wait for all direct I/O to complete.
-        */
+       /* Now wait for all direct I/O to complete. */
        inode_dio_wait(inode);
 
        /*
index 4b33ef112400cc01507b96632d93775839573d99..365dd57ea760ddd5beaa87d78dc6a1f31d7feb94 100644 (file)
@@ -300,8 +300,10 @@ xfs_fs_commit_blocks(
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
        error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
-       if (error)
+       if (error) {
+               xfs_trans_cancel(tp, 0);
                goto out_drop_iolock;
+       }
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
index 53cc2aaf8d2bdfedc12247ae5055feaa95ae31a6..fbbb9e62e274b525a03e7cb1373cae35b49ace1b 100644 (file)
@@ -836,6 +836,11 @@ xfs_qm_reset_dqcounts(
                 */
                xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR,
                            "xfs_quotacheck");
+               /*
+                * Reset type in case we are reusing group quota file for
+                * project quotas or vice versa
+                */
+               ddq->d_flags = type;
                ddq->d_bcount = 0;
                ddq->d_icount = 0;
                ddq->d_rtbcount = 0;
index a24addfdfcec5568015e4e358402d6afa002e37a..0de6290df4da65f1511658c0ae0bc60bf24679fa 100644 (file)
@@ -68,8 +68,8 @@ struct drm_mm_node {
        unsigned scanned_preceeds_hole : 1;
        unsigned allocated : 1;
        unsigned long color;
-       unsigned long start;
-       unsigned long size;
+       u64 start;
+       u64 size;
        struct drm_mm *mm;
 };
 
@@ -82,16 +82,16 @@ struct drm_mm {
        unsigned int scan_check_range : 1;
        unsigned scan_alignment;
        unsigned long scan_color;
-       unsigned long scan_size;
-       unsigned long scan_hit_start;
-       unsigned long scan_hit_end;
+       u64 scan_size;
+       u64 scan_hit_start;
+       u64 scan_hit_end;
        unsigned scanned_blocks;
-       unsigned long scan_start;
-       unsigned long scan_end;
+       u64 scan_start;
+       u64 scan_end;
        struct drm_mm_node *prev_scanned_node;
 
        void (*color_adjust)(struct drm_mm_node *node, unsigned long color,
-                            unsigned long *start, unsigned long *end);
+                            u64 *start, u64 *end);
 };
 
 /**
@@ -124,7 +124,7 @@ static inline bool drm_mm_initialized(struct drm_mm *mm)
        return mm->hole_stack.next;
 }
 
-static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
+static inline u64 __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
        return hole_node->start + hole_node->size;
 }
@@ -140,13 +140,13 @@ static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_no
  * Returns:
  * Start of the subsequent hole.
  */
-static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
+static inline u64 drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
        BUG_ON(!hole_node->hole_follows);
        return __drm_mm_hole_node_start(hole_node);
 }
 
-static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
+static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 {
        return list_entry(hole_node->node_list.next,
                          struct drm_mm_node, node_list)->start;
@@ -163,7 +163,7 @@ static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node
  * Returns:
  * End of the subsequent hole.
  */
-static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
+static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 {
        return __drm_mm_hole_node_end(hole_node);
 }
@@ -222,7 +222,7 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);
 
 int drm_mm_insert_node_generic(struct drm_mm *mm,
                               struct drm_mm_node *node,
-                              unsigned long size,
+                              u64 size,
                               unsigned alignment,
                               unsigned long color,
                               enum drm_mm_search_flags sflags,
@@ -245,7 +245,7 @@ int drm_mm_insert_node_generic(struct drm_mm *mm,
  */
 static inline int drm_mm_insert_node(struct drm_mm *mm,
                                     struct drm_mm_node *node,
-                                    unsigned long size,
+                                    u64 size,
                                     unsigned alignment,
                                     enum drm_mm_search_flags flags)
 {
@@ -255,11 +255,11 @@ static inline int drm_mm_insert_node(struct drm_mm *mm,
 
 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
                                        struct drm_mm_node *node,
-                                       unsigned long size,
+                                       u64 size,
                                        unsigned alignment,
                                        unsigned long color,
-                                       unsigned long start,
-                                       unsigned long end,
+                                       u64 start,
+                                       u64 end,
                                        enum drm_mm_search_flags sflags,
                                        enum drm_mm_allocator_flags aflags);
 /**
@@ -282,10 +282,10 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
  */
 static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
                                              struct drm_mm_node *node,
-                                             unsigned long size,
+                                             u64 size,
                                              unsigned alignment,
-                                             unsigned long start,
-                                             unsigned long end,
+                                             u64 start,
+                                             u64 end,
                                              enum drm_mm_search_flags flags)
 {
        return drm_mm_insert_node_in_range_generic(mm, node, size, alignment,
@@ -296,21 +296,21 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
 void drm_mm_remove_node(struct drm_mm_node *node);
 void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
 void drm_mm_init(struct drm_mm *mm,
-                unsigned long start,
-                unsigned long size);
+                u64 start,
+                u64 size);
 void drm_mm_takedown(struct drm_mm *mm);
 bool drm_mm_clean(struct drm_mm *mm);
 
 void drm_mm_init_scan(struct drm_mm *mm,
-                     unsigned long size,
+                     u64 size,
                      unsigned alignment,
                      unsigned long color);
 void drm_mm_init_scan_with_range(struct drm_mm *mm,
-                                unsigned long size,
+                                u64 size,
                                 unsigned alignment,
                                 unsigned long color,
-                                unsigned long start,
-                                unsigned long end);
+                                u64 start,
+                                u64 end);
 bool drm_mm_scan_add_block(struct drm_mm_node *node);
 bool drm_mm_scan_remove_block(struct drm_mm_node *node);
 
index 180ad0e6de21dd3f0332335f90c122692a553838..d016dc57f0073eede1a5467b798fa35dfa779da5 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 0ccf7f267ff94408387d71da446cc89ab1caf6fa..c768ddfbe53ccbbfeedd92809a9d4036adfc1fe2 100644 (file)
@@ -249,7 +249,7 @@ struct ttm_buffer_object {
         * either of these locks held.
         */
 
-       unsigned long offset;
+       uint64_t offset; /* GPU address space is independent of CPU word size */
        uint32_t cur_placement;
 
        struct sg_table *sg;
index 142d752fc450b74b60e964dd6a5c3d12ba38b163..813042cede5728a1bc3e8d463006217d49f35483 100644 (file)
@@ -277,7 +277,7 @@ struct ttm_mem_type_manager {
        bool has_type;
        bool use_type;
        uint32_t flags;
-       unsigned long gpu_offset;
+       uint64_t gpu_offset; /* GPU address space is independent of CPU word size */
        uint64_t size;
        uint32_t available_caching;
        uint32_t default_caching;
index 2fbc804e1a45cea943c9241309601f941abd5d14..226f77246a70c689f34c6720f1796cf59b4b8a3b 100644 (file)
@@ -13,7 +13,8 @@
 
 #define PULL_DISABLE           (1 << 3)
 #define INPUT_EN               (1 << 5)
-#define SLEWCTRL_FAST          (1 << 6)
+#define SLEWCTRL_SLOW          (1 << 6)
+#define SLEWCTRL_FAST          0
 
 /* update macro depending on INPUT_EN and PULL_ENA */
 #undef PIN_OUTPUT
index 9c2e4f82381e8abc7b21ac59447fefb84d5a1ea3..5f4d01898c9c153ff73feebd46930524a2d50a4d 100644 (file)
@@ -18,7 +18,8 @@
 #define PULL_DISABLE           (1 << 16)
 #define PULL_UP                        (1 << 17)
 #define INPUT_EN               (1 << 18)
-#define SLEWCTRL_FAST          (1 << 19)
+#define SLEWCTRL_SLOW          (1 << 19)
+#define SLEWCTRL_FAST          0
 #define DS0_PULL_UP_DOWN_EN    (1 << 27)
 
 #define PIN_OUTPUT             (PULL_DISABLE)
index 7c55dd5dd2c9faf2202692ca5f669f064c173ed4..66203b268984ebedd72d5bd1b2f54440e56011bc 100644 (file)
@@ -114,6 +114,7 @@ struct vgic_ops {
        void    (*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
        u64     (*get_elrsr)(const struct kvm_vcpu *vcpu);
        u64     (*get_eisr)(const struct kvm_vcpu *vcpu);
+       void    (*clear_eisr)(struct kvm_vcpu *vcpu);
        u32     (*get_interrupt_status)(const struct kvm_vcpu *vcpu);
        void    (*enable_underflow)(struct kvm_vcpu *vcpu);
        void    (*disable_underflow)(struct kvm_vcpu *vcpu);
index 8381bbfbc3085bcde157c02ea7234826f757a1e8..68c16a6bedb36462c3cec290c9eee81abe2072f9 100644 (file)
@@ -125,6 +125,19 @@ int clk_set_phase(struct clk *clk, int degrees);
  */
 int clk_get_phase(struct clk *clk);
 
+/**
+ * clk_is_match - check if two clk's point to the same hardware clock
+ * @p: clk compared against q
+ * @q: clk compared against p
+ *
+ * Returns true if the two struct clk pointers both point to the same hardware
+ * clock node. Put differently, returns true if struct clk *p and struct clk *q
+ * share the same struct clk_core object.
+ *
+ * Returns false otherwise. Note that two NULL clks are treated as matching.
+ */
+bool clk_is_match(const struct clk *p, const struct clk *q);
+
 #else
 
 static inline long clk_get_accuracy(struct clk *clk)
@@ -142,6 +155,11 @@ static inline long clk_get_phase(struct clk *clk)
        return -ENOTSUPP;
 }
 
+static inline bool clk_is_match(const struct clk *p, const struct clk *q)
+{
+       return p == q;
+}
+
 #endif
 
 /**
index f551a9299ac987c5121a6f58383a953a8704d729..306178d7309f193cb32443f49c888297ffa9573e 100644 (file)
@@ -126,6 +126,8 @@ struct cpuidle_driver {
 
 #ifdef CONFIG_CPU_IDLE
 extern void disable_cpuidle(void);
+extern bool cpuidle_not_available(struct cpuidle_driver *drv,
+                                 struct cpuidle_device *dev);
 
 extern int cpuidle_select(struct cpuidle_driver *drv,
                          struct cpuidle_device *dev);
@@ -150,11 +152,17 @@ extern void cpuidle_resume(void);
 extern int cpuidle_enable_device(struct cpuidle_device *dev);
 extern void cpuidle_disable_device(struct cpuidle_device *dev);
 extern int cpuidle_play_dead(void);
-extern void cpuidle_enter_freeze(void);
+extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                                     struct cpuidle_device *dev);
+extern int cpuidle_enter_freeze(struct cpuidle_driver *drv,
+                               struct cpuidle_device *dev);
 
 extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
 #else
 static inline void disable_cpuidle(void) { }
+static inline bool cpuidle_not_available(struct cpuidle_driver *drv,
+                                        struct cpuidle_device *dev)
+{return true; }
 static inline int cpuidle_select(struct cpuidle_driver *drv,
                                 struct cpuidle_device *dev)
 {return -ENODEV; }
@@ -183,7 +191,12 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev)
 {return -ENODEV; }
 static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
 static inline int cpuidle_play_dead(void) {return -ENODEV; }
-static inline void cpuidle_enter_freeze(void) { }
+static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
+                                            struct cpuidle_device *dev)
+{return -ENODEV; }
+static inline int cpuidle_enter_freeze(struct cpuidle_driver *drv,
+                                      struct cpuidle_device *dev)
+{return -ENODEV; }
 static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
        struct cpuidle_device *dev) {return NULL; }
 #endif
index 2646aed1d3fedad16a773eaa366edad3ab44bad5..fd23978d93fe35a91afab5f56d3611c0324d9ceb 100644 (file)
@@ -375,6 +375,7 @@ int dm_create(int minor, struct mapped_device **md);
  */
 struct mapped_device *dm_get_md(dev_t dev);
 void dm_get(struct mapped_device *md);
+int dm_hold(struct mapped_device *md);
 void dm_put(struct mapped_device *md);
 
 /*
index b4d71b5e1ff23a2d3f3ec5c481937edd571ead4d..f4131e8ead74965a73272949b3a9eae8fa08b5c7 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 51f7ccadf923c337ddb5627491a958c5e74fa610..4173a8fdad9efd052870b8738547ac1fa1962526 100644 (file)
@@ -33,6 +33,8 @@
  * @units:             Measurment unit for this attribute.
  * @unit_expo:         Exponent used in the data.
  * @size:              Size in bytes for data size.
+ * @logical_minimum:   Logical minimum value for this attribute.
+ * @logical_maximum:   Logical maximum value for this attribute.
  */
 struct hid_sensor_hub_attribute_info {
        u32 usage_id;
@@ -146,6 +148,7 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
 
 /**
 * sensor_hub_input_attr_get_raw_value() - Synchronous read request
+* @hsdev:      Hub device instance.
 * @usage_id:   Attribute usage id of parent physical device as per spec
 * @attr_usage_id:      Attribute usage id as per spec
 * @report_id:  Report id to look for
@@ -160,6 +163,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
                        u32 attr_usage_id, u32 report_id);
 /**
 * sensor_hub_set_feature() - Feature set request
+* @hsdev:      Hub device instance.
 * @report_id:  Report id to look for
 * @field_index:        Field index inside a report
 * @value:      Value to set
@@ -172,6 +176,7 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
 
 /**
 * sensor_hub_get_feature() - Feature get request
+* @hsdev:      Hub device instance.
 * @report_id:  Report id to look for
 * @field_index:        Field index inside a report
 * @value:      Place holder for return value
index d9b05b5bf8c7954f63ace548e0a6348f5fa0e327..2e88580194f0238430de1255c5a63f99bf975e0a 100644 (file)
  * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
  *                Used by threaded interrupts which need to keep the
  *                irq line disabled until the threaded handler has been run.
- * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
+ * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend.  Does not guarantee
+ *                   that this interrupt will wake the system from a suspended
+ *                   state.  See Documentation/power/suspend-and-interrupts.txt
  * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
  * IRQF_NO_THREAD - Interrupt cannot be threaded
  * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
  *                resume time.
+ * IRQF_COND_SUSPEND - If the IRQ is shared with a NO_SUSPEND user, execute this
+ *                interrupt handler after suspending interrupts. For system
+ *                wakeup devices users need to implement wakeup detection in
+ *                their interrupt handlers.
  */
 #define IRQF_DISABLED          0x00000020
 #define IRQF_SHARED            0x00000080
@@ -70,6 +76,7 @@
 #define IRQF_FORCE_RESUME      0x00008000
 #define IRQF_NO_THREAD         0x00010000
 #define IRQF_EARLY_RESUME      0x00020000
+#define IRQF_COND_SUSPEND      0x00040000
 
 #define IRQF_TIMER             (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
 
index 800544bc7bfdd7f0fdda6fb96e6be104870d9d9a..ffbc034c88104d251c3891f4513c12a62818c5dd 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 faf433af425e41e2da532939af63ec258f8fd619..dd1109fb241e42263e5851ddbc325f469c42a87c 100644 (file)
@@ -78,6 +78,7 @@ struct irq_desc {
 #ifdef CONFIG_PM_SLEEP
        unsigned int            nr_actions;
        unsigned int            no_suspend_depth;
+       unsigned int            cond_suspend_depth;
        unsigned int            force_resume_depth;
 #endif
 #ifdef CONFIG_PROC_FS
index 72ba725ddf9c73054533256a7246f5425c95771b..5bb074431eb0ce571b32d785b45ad85ee8c22b34 100644 (file)
@@ -5,6 +5,7 @@
 
 struct kmem_cache;
 struct page;
+struct vm_struct;
 
 #ifdef CONFIG_KASAN
 
@@ -49,15 +50,11 @@ void kasan_krealloc(const void *object, size_t new_size);
 void kasan_slab_alloc(struct kmem_cache *s, void *object);
 void kasan_slab_free(struct kmem_cache *s, void *object);
 
-#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
-
 int kasan_module_alloc(void *addr, size_t size);
-void kasan_module_free(void *addr);
+void kasan_free_shadow(const struct vm_struct *vm);
 
 #else /* CONFIG_KASAN */
 
-#define MODULE_ALIGN 1
-
 static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
 
 static inline void kasan_enable_current(void) {}
@@ -82,7 +79,7 @@ static inline void kasan_slab_alloc(struct kmem_cache *s, void *object) {}
 static inline void kasan_slab_free(struct kmem_cache *s, void *object) {}
 
 static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
-static inline void kasan_module_free(void *addr) {}
+static inline void kasan_free_shadow(const struct vm_struct *vm) {}
 
 #endif /* CONFIG_KASAN */
 
index 7bf01d779b4532a5a8d168d0ff91fd08d5228e02..1ce79a7f1daa18868adfe14598c35206382f58a5 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 fc03efa64ffe58ae9aa81e77bf60e5d7b4acc6c7..6b08cc106c218dc06d60988663c4bcac3eaba5fe 100644 (file)
@@ -232,6 +232,7 @@ enum {
                                              * led */
        ATA_FLAG_NO_DIPM        = (1 << 23), /* host not happy with DIPM */
        ATA_FLAG_LOWTAG         = (1 << 24), /* host wants lowest available tag */
+       ATA_FLAG_SAS_HOST       = (1 << 25), /* SAS host */
 
        /* bits 24:31 of ap->flags are reserved for LLD specific flags */
 
index fb0390a1a498f29df135bbe7500c1dfcc00a27d7..ee7b1ce7a6f8f42280abcc3d1411f7bcdebb6ac2 100644 (file)
@@ -2999,6 +2999,9 @@ enum usb_irq_events {
 #define PALMAS_GPADC_TRIM15                                    0x0E
 #define PALMAS_GPADC_TRIM16                                    0x0F
 
+/* TPS659038 regen2_ctrl offset iss different from palmas */
+#define TPS659038_REGEN2_CTRL                                  0x12
+
 /* TPS65917 Interrupt registers */
 
 /* Registers for function INTERRUPT */
index 2bbc62aa818a374d1c488f2eecf4232230bd3f4e..551f85456c11574a144bf64d1c38ec8031313b3e 100644 (file)
@@ -427,7 +427,7 @@ struct mlx4_wqe_inline_seg {
 
 enum mlx4_update_qp_attr {
        MLX4_UPDATE_QP_SMAC             = 1 << 0,
-       MLX4_UPDATE_QP_VSD              = 1 << 2,
+       MLX4_UPDATE_QP_VSD              = 1 << 1,
        MLX4_UPDATE_QP_SUPPORTED_ATTRS  = (1 << 2) - 1
 };
 
index 42999fe2dbd0fb8ec057dbd07d4c2143d6225c65..b03485bcb82a0a4d1f6ebbbac8b30f37beb722a2 100644 (file)
@@ -344,6 +344,10 @@ struct module {
        unsigned long *ftrace_callsites;
 #endif
 
+#ifdef CONFIG_LIVEPATCH
+       bool klp_alive;
+#endif
+
 #ifdef CONFIG_MODULE_UNLOAD
        /* What modules depend on me? */
        struct list_head source_list;
index f7556261fe3c54adb52b28789b7cb7b19b280b13..4d0cb9bba93e4650d76b314cc50160e5b8e7e65d 100644 (file)
@@ -84,4 +84,12 @@ void module_arch_cleanup(struct module *mod);
 
 /* Any cleanup before freeing mod->module_init */
 void module_arch_freeing_init(struct module *mod);
+
+#ifdef CONFIG_KASAN
+#include <linux/kasan.h>
+#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
+#else
+#define MODULE_ALIGN PAGE_SIZE
+#endif
+
 #endif
index 5897b4ea5a3f9e0f07f511f57d8fa8bfe7019205..278738873703c119dfa322c13b2755e2176a61f5 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 2f77e0c651c89874a641c8a04a723aaf60dd2837..b01ccf371fdcaf229f07bddbd2f12f9bbb5c53b0 100644 (file)
@@ -343,6 +343,7 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
+extern int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
 extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
@@ -355,8 +356,9 @@ extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
 extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+extern int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping);
 extern int nfs_setattr(struct dentry *, struct iattr *);
-extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
+extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *);
 extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
                                struct nfs4_label *label);
 extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
@@ -369,6 +371,7 @@ extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ct
 extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);
 extern u64 nfs_compat_user_ino64(u64 fileid);
 extern void nfs_fattr_init(struct nfs_fattr *fattr);
+extern void nfs_fattr_set_barrier(struct nfs_fattr *fattr);
 extern unsigned long nfs_inc_attr_generation_counter(void);
 
 extern struct nfs_fattr *nfs_alloc_fattr(void);
index 8a860f096c351fa93267dabaebab8f3c7605ac18..611a691145c48d7c38c370daa63b047b5c68c17a 100644 (file)
@@ -84,7 +84,7 @@ static inline int of_platform_populate(struct device_node *root,
 static inline void of_platform_depopulate(struct device *parent) { }
 #endif
 
-#ifdef CONFIG_OF_DYNAMIC
+#if defined(CONFIG_OF_DYNAMIC) && defined(CONFIG_OF_ADDRESS)
 extern void of_platform_register_reconfig_notifier(void);
 #else
 static inline void of_platform_register_reconfig_notifier(void) { }
index 72c0415d6c21758d31fcd2ab80c33751e41489d5..18eccefea06e40a0ea10f77e857105c6feaf4ff9 100644 (file)
@@ -82,7 +82,7 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio)
 
 static inline struct pinctrl * __must_check pinctrl_get(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline void pinctrl_put(struct pinctrl *p)
@@ -93,7 +93,7 @@ static inline struct pinctrl_state * __must_check pinctrl_lookup_state(
                                                        struct pinctrl *p,
                                                        const char *name)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline int pinctrl_select_state(struct pinctrl *p,
@@ -104,7 +104,7 @@ static inline int pinctrl_select_state(struct pinctrl *p,
 
 static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
 {
-       return ERR_PTR(-ENOSYS);
+       return NULL;
 }
 
 static inline void devm_pinctrl_put(struct pinctrl *p)
index d4ad5b5a02bb478a422b349406efba00997bab76..045f709cb89b52c5e2381635b0bea10101030120 100644 (file)
@@ -316,7 +316,7 @@ struct regulator_desc {
  * @driver_data: private regulator data
  * @of_node: OpenFirmware node to parse for device tree bindings (may be
  *           NULL).
- * @regmap: regmap to use for core regmap helpers if dev_get_regulator() is
+ * @regmap: regmap to use for core regmap helpers if dev_get_regmap() is
  *          insufficient.
  * @ena_gpio_initialized: GPIO controlling regulator enable was properly
  *                        initialized, meaning that >= 0 is a valid gpio
index 58851275fed98c352fdd4995e95f1ebe806649e7..d438eeb08bff407043b32d5f52f58d08fac8838f 100644 (file)
@@ -54,10 +54,11 @@ struct rhash_head {
  * @buckets: size * hash buckets
  */
 struct bucket_table {
-       size_t                          size;
-       unsigned int                    locks_mask;
-       spinlock_t                      *locks;
-       struct rhash_head __rcu         *buckets[];
+       size_t                  size;
+       unsigned int            locks_mask;
+       spinlock_t              *locks;
+
+       struct rhash_head __rcu *buckets[] ____cacheline_aligned_in_smp;
 };
 
 typedef u32 (*rht_hashfn_t)(const void *data, u32 len, u32 seed);
@@ -78,12 +79,6 @@ struct rhashtable;
  * @locks_mul: Number of bucket locks to allocate per cpu (default: 128)
  * @hashfn: Function to hash key
  * @obj_hashfn: Function to hash object
- * @grow_decision: If defined, may return true if table should expand
- * @shrink_decision: If defined, may return true if table should shrink
- *
- * Note: when implementing the grow and shrink decision function, min/max
- * shift must be enforced, otherwise, resizing watermarks they set may be
- * useless.
  */
 struct rhashtable_params {
        size_t                  nelem_hint;
@@ -97,10 +92,6 @@ struct rhashtable_params {
        size_t                  locks_mul;
        rht_hashfn_t            hashfn;
        rht_obj_hashfn_t        obj_hashfn;
-       bool                    (*grow_decision)(const struct rhashtable *ht,
-                                                size_t new_size);
-       bool                    (*shrink_decision)(const struct rhashtable *ht,
-                                                  size_t new_size);
 };
 
 /**
@@ -192,9 +183,6 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params);
 void rhashtable_insert(struct rhashtable *ht, struct rhash_head *node);
 bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *node);
 
-bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size);
-bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size);
-
 int rhashtable_expand(struct rhashtable *ht);
 int rhashtable_shrink(struct rhashtable *ht);
 
index 6d77432e14ff971bffd4ca211dccb917768b2c8c..a419b65770d669c3a51c88a86a145abbcd3db339 100644 (file)
@@ -1625,11 +1625,11 @@ struct task_struct {
 
        /*
         * numa_faults_locality tracks if faults recorded during the last
-        * scan window were remote/local. The task scan period is adapted
-        * based on the locality of the faults with different weights
-        * depending on whether they were shared or private faults
+        * scan window were remote/local or failed to migrate. The task scan
+        * period is adapted based on the locality of the faults with different
+        * weights depending on whether they were shared or private faults
         */
-       unsigned long numa_faults_locality[2];
+       unsigned long numa_faults_locality[3];
 
        unsigned long numa_pages_migrated;
 #endif /* CONFIG_NUMA_BALANCING */
@@ -1719,6 +1719,7 @@ struct task_struct {
 #define TNF_NO_GROUP   0x02
 #define TNF_SHARED     0x04
 #define TNF_FAULT_LOCAL        0x08
+#define TNF_MIGRATE_FAIL 0x10
 
 #ifdef CONFIG_NUMA_BALANCING
 extern void task_numa_fault(int last_node, int node, int pages, int flags);
index baf3e1d08416faaf34edd51bca72c2801e7e7e06..d10965f0d8a4af6526a07046ba040ae9708279a4 100644 (file)
@@ -143,13 +143,13 @@ struct uart_port {
        unsigned char           iotype;                 /* io access style */
        unsigned char           unused1;
 
-#define UPIO_PORT              (0)                     /* 8b I/O port access */
-#define UPIO_HUB6              (1)                     /* Hub6 ISA card */
-#define UPIO_MEM               (2)                     /* 8b MMIO access */
-#define UPIO_MEM32             (3)                     /* 32b little endian */
-#define UPIO_MEM32BE           (4)                     /* 32b big endian */
-#define UPIO_AU                        (5)                     /* Au1x00 and RT288x type IO */
-#define UPIO_TSI               (6)                     /* Tsi108/109 type IO */
+#define UPIO_PORT              (SERIAL_IO_PORT)        /* 8b I/O port access */
+#define UPIO_HUB6              (SERIAL_IO_HUB6)        /* Hub6 ISA card */
+#define UPIO_MEM               (SERIAL_IO_MEM)         /* 8b MMIO access */
+#define UPIO_MEM32             (SERIAL_IO_MEM32)       /* 32b little endian */
+#define UPIO_AU                        (SERIAL_IO_AU)          /* Au1x00 and RT288x type IO */
+#define UPIO_TSI               (SERIAL_IO_TSI)         /* Tsi108/109 type IO */
+#define UPIO_MEM32BE           (SERIAL_IO_MEM32BE)     /* 32b big endian */
 
        unsigned int            read_status_mask;       /* driver specific */
        unsigned int            ignore_status_mask;     /* driver specific */
index 30007afe70b3541cdb4300919c2a5cfbbc0063f2..f54d6659713ae76e96391334dba700eac8be122f 100644 (file)
@@ -948,6 +948,13 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
        to->l4_hash = from->l4_hash;
 };
 
+static inline void skb_sender_cpu_clear(struct sk_buff *skb)
+{
+#ifdef CONFIG_XPS
+       skb->sender_cpu = 0;
+#endif
+}
+
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 {
index ed9489d893a487f250868f8de603c84e707feaf8..856d34dde79bc9d81faae4171fb0c5492829c133 100644 (file)
@@ -649,7 +649,7 @@ struct spi_transfer {
  * sequence completes.  On some systems, many such sequences can execute as
  * as single programmed DMA transfer.  On all systems, these messages are
  * queued, and might complete after transactions to other devices.  Messages
- * sent to a given spi_device are alway executed in FIFO order.
+ * sent to a given spi_device are always executed in FIFO order.
  *
  * The code that submits an spi_message (and its spi_transfers)
  * to the lower layers is responsible for managing its memory.
index c57d8ea0716cddea1419a37481dbd7704b230d65..59a7889e15db51c3b24bc771dbe5d0b1c965212d 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 fc52e307efab8768effbb7880702986653e0a07c..5eac316490eab9ca0ad1a864be2b6fedb823f332 100644 (file)
@@ -314,6 +314,8 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
 }
 
 #endif
+
+#if IS_ENABLED(CONFIG_THERMAL)
 struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
                void *, struct thermal_zone_device_ops *,
                const struct thermal_zone_params *, int, int);
@@ -340,8 +342,58 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
                struct thermal_cooling_device *, int);
 void thermal_cdev_update(struct thermal_cooling_device *);
 void thermal_notify_framework(struct thermal_zone_device *, int);
-
-#ifdef CONFIG_NET
+#else
+static inline struct thermal_zone_device *thermal_zone_device_register(
+       const char *type, int trips, int mask, void *devdata,
+       struct thermal_zone_device_ops *ops,
+       const struct thermal_zone_params *tzp,
+       int passive_delay, int polling_delay)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_zone_device_unregister(
+       struct thermal_zone_device *tz)
+{ }
+static inline int thermal_zone_bind_cooling_device(
+       struct thermal_zone_device *tz, int trip,
+       struct thermal_cooling_device *cdev,
+       unsigned long upper, unsigned long lower)
+{ return -ENODEV; }
+static inline int thermal_zone_unbind_cooling_device(
+       struct thermal_zone_device *tz, int trip,
+       struct thermal_cooling_device *cdev)
+{ return -ENODEV; }
+static inline void thermal_zone_device_update(struct thermal_zone_device *tz)
+{ }
+static inline struct thermal_cooling_device *
+thermal_cooling_device_register(char *type, void *devdata,
+       const struct thermal_cooling_device_ops *ops)
+{ return ERR_PTR(-ENODEV); }
+static inline struct thermal_cooling_device *
+thermal_of_cooling_device_register(struct device_node *np,
+       char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_cooling_device_unregister(
+       struct thermal_cooling_device *cdev)
+{ }
+static inline struct thermal_zone_device *thermal_zone_get_zone_by_name(
+               const char *name)
+{ return ERR_PTR(-ENODEV); }
+static inline int thermal_zone_get_temp(
+               struct thermal_zone_device *tz, unsigned long *temp)
+{ return -ENODEV; }
+static inline int get_tz_trend(struct thermal_zone_device *tz, int trip)
+{ return -ENODEV; }
+static inline struct thermal_instance *
+get_thermal_instance(struct thermal_zone_device *tz,
+       struct thermal_cooling_device *cdev, int trip)
+{ return ERR_PTR(-ENODEV); }
+static inline void thermal_cdev_update(struct thermal_cooling_device *cdev)
+{ }
+static inline void thermal_notify_framework(struct thermal_zone_device *tz,
+       int trip)
+{ }
+#endif /* CONFIG_THERMAL */
+
+#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL)
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
                                                enum events event);
 #else
index 07a022641996f0ccf74cd872ccd9e4bc8aa5f538..71880299ed487b68dc7b278248a4fb29ddb6b6ec 100644 (file)
@@ -98,6 +98,8 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
                        size_t maxsize, size_t *start);
 int iov_iter_npages(const struct iov_iter *i, int maxpages);
 
+const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags);
+
 static inline size_t iov_iter_count(struct iov_iter *i)
 {
        return i->count;
index 9bb547c7bce7c7ce0942fdb4e313188d4878b371..704a1ab8240ca124f29c5ce361c871090d28ea5b 100644 (file)
@@ -190,8 +190,7 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
  * @num_ports: the number of different ports this device will have.
  * @bulk_in_size: minimum number of bytes to allocate for bulk-in buffer
  *     (0 = end-point size)
- * @bulk_out_size: minimum number of bytes to allocate for bulk-out buffer
- *     (0 = end-point size)
+ * @bulk_out_size: bytes to allocate for bulk-out buffer (0 = end-point size)
  * @calc_num_ports: pointer to a function to determine how many ports this
  *     device has dynamically.  It will be called after the probe()
  *     callback is called, but before attach()
index d9a4905e01d0c98b88e89c7db5c85bbf7d5be8a1..6e0ce8c7b8cb5a9fcb985a5a5078f82267d03092 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 7d7acb35603d6d6e4bb8a468fcb635d666fea001..0ec598381f9766182db52f246afc2f0a5f28b36f 100644 (file)
@@ -17,6 +17,7 @@ struct vm_area_struct;                /* vma defining user mapping in mm_types.h */
 #define VM_VPAGES              0x00000010      /* buffer for pages was vmalloc'ed */
 #define VM_UNINITIALIZED       0x00000020      /* vm_struct is not fully initialized */
 #define VM_NO_GUARD            0x00000040      /* don't add guard page */
+#define VM_KASAN               0x00000080      /* has allocated kasan shadow memory */
 /* bits [20..32] reserved for arch specific ioremap internals */
 
 /*
index 74db135f99571e37f61e0aecc34d7b5ddba66756..f597846ff605cccaaf36d3cc4e6d603b630af156 100644 (file)
@@ -70,7 +70,8 @@ enum {
        /* data contains off-queue information when !WORK_STRUCT_PWQ */
        WORK_OFFQ_FLAG_BASE     = WORK_STRUCT_COLOR_SHIFT,
 
-       WORK_OFFQ_CANCELING     = (1 << WORK_OFFQ_FLAG_BASE),
+       __WORK_OFFQ_CANCELING   = WORK_OFFQ_FLAG_BASE,
+       WORK_OFFQ_CANCELING     = (1 << __WORK_OFFQ_CANCELING),
 
        /*
         * When a work item is off queue, its high bits point to the last
index 00048339c23e4f252ee6a4b15cd38b49b8032de4..b2dd371ec0ca0aa6f0e1dc71d1f79c69c6dbdb2b 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 1c1ad46250d5c9e0abb0910f1b7debaa6aaa9608..fe328c52c46bd179b651d6bbb14e58a89f017557 100644 (file)
@@ -171,7 +171,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos);
  * @return    Checksum of buffer.
  */
 
-u16 cfpkt_iterate(struct cfpkt *pkt,
+int cfpkt_iterate(struct cfpkt *pkt,
                u16 (*iter_func)(u16 chks, void *buf, u16 len),
                u16 data);
 
index a8ae4e760778d8fe49ff21951bd1e088ac3aefca..0fb99a26e97372613da1851d9ee4d9bb432aba3f 100644 (file)
@@ -481,6 +481,7 @@ void dst_init(void);
 enum {
        XFRM_LOOKUP_ICMP = 1 << 0,
        XFRM_LOOKUP_QUEUE = 1 << 1,
+       XFRM_LOOKUP_KEEP_DST_REF = 1 << 2,
 };
 
 struct flowi;
index 025c61c0dffbfe9ddfcc2cd6f9eb38b2af504d3f..6cc1eafb153a75c4665f375836f5592c282f9a8f 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 1d09b46c1e489325b95f9987327d95ca8affed08..eda131d179d971147f5b7ac254876dbf07946861 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 534e1f2ac4fc36d5baeb7b3115dc95aaebd065d9..57639fca223a69823a48cecff03078387a917084 100644 (file)
@@ -79,6 +79,16 @@ void nf_log_packet(struct net *net,
                   const struct nf_loginfo *li,
                   const char *fmt, ...);
 
+__printf(8, 9)
+void nf_log_trace(struct net *net,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *li,
+                 const char *fmt, ...);
+
 struct nf_log_buf;
 
 struct nf_log_buf *nf_log_buf_open(void);
index 9eaaa788458607004cb5f160e77c38de02da17ec..decb9a095ae7c4df5ace79f366762138c223958c 100644 (file)
@@ -119,6 +119,22 @@ int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
                           const struct nft_data *data,
                           enum nft_data_types type);
 
+
+/**
+ *     struct nft_userdata - user defined data associated with an object
+ *
+ *     @len: length of the data
+ *     @data: content
+ *
+ *     The presence of user data is indicated in an object specific fashion,
+ *     so a length of zero can't occur and the value "len" indicates data
+ *     of length len + 1.
+ */
+struct nft_userdata {
+       u8                      len;
+       unsigned char           data[0];
+};
+
 /**
  *     struct nft_set_elem - generic representation of set elements
  *
@@ -380,7 +396,7 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
  *     @handle: rule handle
  *     @genmask: generation mask
  *     @dlen: length of expression data
- *     @ulen: length of user data (used for comments)
+ *     @udata: user data is appended to the rule
  *     @data: expression data
  */
 struct nft_rule {
@@ -388,7 +404,7 @@ struct nft_rule {
        u64                             handle:42,
                                        genmask:2,
                                        dlen:12,
-                                       ulen:8;
+                                       udata:1;
        unsigned char                   data[]
                __attribute__((aligned(__alignof__(struct nft_expr))));
 };
@@ -476,7 +492,7 @@ static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule)
        return (struct nft_expr *)&rule->data[rule->dlen];
 }
 
-static inline void *nft_userdata(const struct nft_rule *rule)
+static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
 {
        return (void *)&rule->data[rule->dlen];
 }
index ab186b1d31fffe7cc5b4888d85aca99c2d875da4..e4079c28e6b8588da92a8826d63e07195859a33b 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 eabd3a038674dd00f69263b47828134dd3a24bf1..c73e7abbbaa50e917e65a1117e881bd78665b12a 100644 (file)
@@ -91,6 +91,7 @@ struct vxlanhdr {
 
 #define VXLAN_N_VID     (1u << 24)
 #define VXLAN_VID_MASK  (VXLAN_N_VID - 1)
+#define VXLAN_VNI_MASK  (VXLAN_VID_MASK << 8)
 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
 
 struct vxlan_metadata {
index 0210797abf2e95e88f67dd480ae24597325842d3..dc10c52e0e9199e7e878a87a714569106a955df3 100644 (file)
@@ -92,7 +92,7 @@
 #define                AT91_DDRSDRC_UPD_MR     (3 << 20)        /* Update load mode register and extended mode register */
 
 #define AT91_DDRSDRC_MDR       0x20    /* Memory Device Register */
-#define                AT91_DDRSDRC_MD         (3 << 0)                /* Memory Device Type */
+#define                AT91_DDRSDRC_MD         (7 << 0)        /* Memory Device Type */
 #define                        AT91_DDRSDRC_MD_SDR             0
 #define                        AT91_DDRSDRC_MD_LOW_POWER_SDR   1
 #define                        AT91_DDRSDRC_MD_LOW_POWER_DDR   3
index 3c45f3924ba7e779a4d32a357665d0359abcbaaf..c704357775fc4ef077ef52fb27cfb97c75b378ee 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 bd311197a3b5750c48b4bbf0b6471231a13f34ac..b7d60510819b020038ece185977db1d6ea33af93 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 8d7416e46861744d990f4c0dbb2d1f72fdd9407b..0bc83647d3fa39e05fcd153467eec20aa4c74556 100644 (file)
@@ -378,6 +378,7 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
 void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
 int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
                         const struct snd_soc_pcm_stream *params,
+                        unsigned int num_params,
                         struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink);
 
@@ -440,7 +441,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);
 
@@ -531,6 +531,8 @@ struct snd_soc_dapm_widget {
        void *priv;                             /* widget specific data */
        struct regulator *regulator;            /* attached regulator */
        const struct snd_soc_pcm_stream *params; /* params for dai links */
+       unsigned int num_params; /* number of params for dai links */
+       unsigned int params_select; /* currently selected param for dai link */
 
        /* dapm control */
        int reg;                                /* negative reg = no direct dapm */
@@ -586,8 +588,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 98f2ade0266eb9a28ae6340b2908bd8fabea0eca..806059052bfcca4aa9d46ff3b0f061442136e84f 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 0d1ade19562857c7b65157636ac37b2f0222e202..2afdd2e72a868354778ecf65d41f478d8807090a 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;
@@ -941,6 +943,7 @@ struct snd_soc_dai_link {
        int be_id;      /* optional ID for machine driver BE identification */
 
        const struct snd_soc_pcm_stream *params;
+       unsigned int num_params;
 
        unsigned int dai_fmt;           /* format to set on init */
 
@@ -954,6 +957,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 +1077,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 +1269,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 db81c65b8f4857c011a025e5b54026bf7d683f7c..d61be7297b2c88c867acbacadcacfd65045e6c50 100644 (file)
@@ -111,6 +111,7 @@ void        array_free(void *array, int n);
 void   target_core_setup_sub_cits(struct se_subsystem_api *);
 
 /* attribute helpers from target_core_device.c for backend drivers */
+bool   se_dev_check_wce(struct se_device *);
 int    se_dev_set_max_unmap_lba_count(struct se_device *, u32);
 int    se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
 int    se_dev_set_unmap_granularity(struct se_device *, u32);
index 23d561512f64fe65a5165a23d4620f7d457504a4..22317d2b52abcbe194ef8e9964bf179ae7d32846 100644 (file)
@@ -7,27 +7,26 @@
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
-struct device;
-struct regmap;
+#include "../../../drivers/base/regmap/internal.h"
 
 /*
  * Log register events
  */
 DECLARE_EVENT_CLASS(regmap_reg,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val),
+       TP_ARGS(map, reg, val),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   reg             )
-               __field(        unsigned int,   val             )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   reg                     )
+               __field(        unsigned int,   val                     )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->reg = reg;
                __entry->val = val;
        ),
@@ -39,45 +38,45 @@ DECLARE_EVENT_CLASS(regmap_reg,
 
 DEFINE_EVENT(regmap_reg, regmap_reg_write,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DEFINE_EVENT(regmap_reg, regmap_reg_read,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DEFINE_EVENT(regmap_reg, regmap_reg_read_cache,
 
-       TP_PROTO(struct device *dev, unsigned int reg,
+       TP_PROTO(struct regmap *map, unsigned int reg,
                 unsigned int val),
 
-       TP_ARGS(dev, reg, val)
+       TP_ARGS(map, reg, val)
 
 );
 
 DECLARE_EVENT_CLASS(regmap_block,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count),
+       TP_ARGS(map, reg, count),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   reg             )
-               __field(        int,            count           )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   reg                     )
+               __field(        int,            count                   )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->reg = reg;
                __entry->count = count;
        ),
@@ -89,48 +88,48 @@ DECLARE_EVENT_CLASS(regmap_block,
 
 DEFINE_EVENT(regmap_block, regmap_hw_read_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_read_done,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_write_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_block, regmap_hw_write_done,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 TRACE_EVENT(regcache_sync,
 
-       TP_PROTO(struct device *dev, const char *type,
+       TP_PROTO(struct regmap *map, const char *type,
                 const char *status),
 
-       TP_ARGS(dev, type, status),
+       TP_ARGS(map, type, status),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __string(       status,         status          )
-               __string(       type,           type            )
-               __field(        int,            type            )
+               __string(       name,           regmap_name(map)        )
+               __string(       status,         status                  )
+               __string(       type,           type                    )
+               __field(        int,            type                    )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __assign_str(status, status);
                __assign_str(type, type);
        ),
@@ -141,17 +140,17 @@ TRACE_EVENT(regcache_sync,
 
 DECLARE_EVENT_CLASS(regmap_bool,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag),
+       TP_ARGS(map, flag),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        int,            flag            )
+               __string(       name,           regmap_name(map)        )
+               __field(        int,            flag                    )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->flag = flag;
        ),
 
@@ -161,32 +160,32 @@ DECLARE_EVENT_CLASS(regmap_bool,
 
 DEFINE_EVENT(regmap_bool, regmap_cache_only,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag)
+       TP_ARGS(map, flag)
 
 );
 
 DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
 
-       TP_PROTO(struct device *dev, bool flag),
+       TP_PROTO(struct regmap *map, bool flag),
 
-       TP_ARGS(dev, flag)
+       TP_ARGS(map, flag)
 
 );
 
 DECLARE_EVENT_CLASS(regmap_async,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev),
+       TP_ARGS(map),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
+               __string(       name,           regmap_name(map)        )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
        ),
 
        TP_printk("%s", __get_str(name))
@@ -194,50 +193,50 @@ DECLARE_EVENT_CLASS(regmap_async,
 
 DEFINE_EVENT(regmap_block, regmap_async_write_start,
 
-       TP_PROTO(struct device *dev, unsigned int reg, int count),
+       TP_PROTO(struct regmap *map, unsigned int reg, int count),
 
-       TP_ARGS(dev, reg, count)
+       TP_ARGS(map, reg, count)
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_io_complete,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_complete_start,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 DEFINE_EVENT(regmap_async, regmap_async_complete_done,
 
-       TP_PROTO(struct device *dev),
+       TP_PROTO(struct regmap *map),
 
-       TP_ARGS(dev)
+       TP_ARGS(map)
 
 );
 
 TRACE_EVENT(regcache_drop_region,
 
-       TP_PROTO(struct device *dev, unsigned int from,
+       TP_PROTO(struct regmap *map, unsigned int from,
                 unsigned int to),
 
-       TP_ARGS(dev, from, to),
+       TP_ARGS(map, from, to),
 
        TP_STRUCT__entry(
-               __string(       name,           dev_name(dev)   )
-               __field(        unsigned int,   from            )
-               __field(        unsigned int,   to              )
+               __string(       name,           regmap_name(map)        )
+               __field(        unsigned int,   from                    )
+               __field(        unsigned int,   to                      )
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(dev));
+               __assign_str(name, regmap_name(map));
                __entry->from = from;
                __entry->to = to;
        ),
index b0a81307985282005ade90ee6da96e3048c405d3..2f62ab2d7bf99bd75b16eef6db74ce8aa233e8ff 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 4742f2cb42f2bd46180421efef423f101579bd03..d3bd6ffec04101138e831076789fc11cee98f2be 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 5e0d0ed61cf3b76d2ee7cae605834d8139cf73ee..25331f9faa7682a88222d6db22a4213472219d06 100644 (file)
@@ -65,6 +65,10 @@ struct serial_struct {
 #define SERIAL_IO_PORT 0
 #define SERIAL_IO_HUB6 1
 #define SERIAL_IO_MEM  2
+#define SERIAL_IO_MEM32          3
+#define SERIAL_IO_AU     4
+#define SERIAL_IO_TSI    5
+#define SERIAL_IO_MEM32BE 6
 
 #define UART_CLEAR_FIFO                0x01
 #define UART_USE_FIFO          0x02
index 19d5219b0b991eda86a5bb8a0274d35a5a88ce17..242cf0c6e33d37f229a224839ca6f679bb142674 100644 (file)
@@ -9,3 +9,4 @@ header-y += tc_pedit.h
 header-y += tc_skbedit.h
 header-y += tc_vlan.h
 header-y += tc_bpf.h
+header-y += tc_connmark.h
index 3c53eec4ae22697ecb87522bf83de79f4e7e2b0e..19c66fcbab8afb1ee5239140fab657b4fe52ed67 100644 (file)
@@ -60,7 +60,7 @@ struct virtio_blk_config {
        __u32 size_max;
        /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
        __u32 seg_max;
-       /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
+       /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
        struct virtio_blk_geometry {
                __u16 cylinders;
                __u8 heads;
@@ -119,7 +119,11 @@ struct virtio_blk_config {
 #define VIRTIO_BLK_T_BARRIER   0x80000000
 #endif /* !VIRTIO_BLK_NO_LEGACY */
 
-/* This is the first element of the read scatter-gather list. */
+/*
+ * This comes first in the read scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
+ * this is the first element of the read scatter-gather list.
+ */
 struct virtio_blk_outhdr {
        /* VIRTIO_BLK_T* */
        __virtio32 type;
index 42b9370771b014d4b959cd4c0c67a7bcc7eee41d..cc18ef8825c0eddb493a1d1b8bc618f5d3ce74e8 100644 (file)
 
 #include <linux/virtio_types.h>
 
-#define VIRTIO_SCSI_CDB_SIZE   32
-#define VIRTIO_SCSI_SENSE_SIZE 96
+/* Default values of the CDB and sense data size configuration fields */
+#define VIRTIO_SCSI_CDB_DEFAULT_SIZE   32
+#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96
+
+#ifndef VIRTIO_SCSI_CDB_SIZE
+#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE
+#endif
+#ifndef VIRTIO_SCSI_SENSE_SIZE
+#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE
+#endif
 
 /* SCSI command request, followed by data-out */
 struct virtio_scsi_cmd_req {
index 60de61fea8e364069969faa9bc08a7f9e19c4433..c8ed15daad02d37c5a8eec0b3787dfabf8ad9d3f 100644 (file)
@@ -689,6 +689,7 @@ struct omapdss_dsi_ops {
 };
 
 struct omap_dss_device {
+       struct kobject kobj;
        struct device *dev;
 
        struct module *owner;
index 7491ee5d81647d704a7d34ce17e107c7c374b64d..83338210ee045277b785e2af35b11b30b24c1e74 100644 (file)
@@ -46,4 +46,30 @@ static inline efi_system_table_t __init *xen_efi_probe(void)
 }
 #endif
 
+#ifdef CONFIG_PREEMPT
+
+static inline void xen_preemptible_hcall_begin(void)
+{
+}
+
+static inline void xen_preemptible_hcall_end(void)
+{
+}
+
+#else
+
+DECLARE_PER_CPU(bool, xen_in_preemptible_hcall);
+
+static inline void xen_preemptible_hcall_begin(void)
+{
+       __this_cpu_write(xen_in_preemptible_hcall, true);
+}
+
+static inline void xen_preemptible_hcall_end(void)
+{
+       __this_cpu_write(xen_in_preemptible_hcall, false);
+}
+
+#endif /* CONFIG_PREEMPT */
+
 #endif /* INCLUDE_XEN_OPS_H */
index b78f21caf55aa074d3f883d0a0269f1c7d268339..b0f1c9e5d6878117c43a1b3e402e5f97ceb15657 100644 (file)
@@ -114,9 +114,9 @@ int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
                                           const char *mod_name);
 
 #define xenbus_register_frontend(drv) \
-       __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME);
+       __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME)
 #define xenbus_register_backend(drv) \
-       __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME);
+       __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME)
 
 void xenbus_unregister_driver(struct xenbus_driver *drv);
 
index 1d1fe9361d29882369f76e426b56ddd002582d2c..fc7f4748d34a9fe017bd9a42353db7a4095240d2 100644 (file)
@@ -548,9 +548,6 @@ static void update_domain_attr_tree(struct sched_domain_attr *dattr,
 
        rcu_read_lock();
        cpuset_for_each_descendant_pre(cp, pos_css, root_cs) {
-               if (cp == root_cs)
-                       continue;
-
                /* skip the whole subtree if @cp doesn't have any CPU */
                if (cpumask_empty(cp->cpus_allowed)) {
                        pos_css = css_rightmost_descendant(pos_css);
@@ -873,7 +870,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct cpumask *new_cpus)
                 * If it becomes empty, inherit the effective mask of the
                 * parent, which is guaranteed to have some CPUs.
                 */
-               if (cpumask_empty(new_cpus))
+               if (cgroup_on_dfl(cp->css.cgroup) && cpumask_empty(new_cpus))
                        cpumask_copy(new_cpus, parent->effective_cpus);
 
                /* Skip the whole subtree if the cpumask remains the same. */
@@ -1129,7 +1126,7 @@ static void update_nodemasks_hier(struct cpuset *cs, nodemask_t *new_mems)
                 * If it becomes empty, inherit the effective mask of the
                 * parent, which is guaranteed to have some MEMs.
                 */
-               if (nodes_empty(*new_mems))
+               if (cgroup_on_dfl(cp->css.cgroup) && nodes_empty(*new_mems))
                        *new_mems = parent->effective_mems;
 
                /* Skip the whole subtree if the nodemask remains the same. */
@@ -1979,7 +1976,9 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
 
        spin_lock_irq(&callback_lock);
        cs->mems_allowed = parent->mems_allowed;
+       cs->effective_mems = parent->mems_allowed;
        cpumask_copy(cs->cpus_allowed, parent->cpus_allowed);
+       cpumask_copy(cs->effective_cpus, parent->cpus_allowed);
        spin_unlock_irq(&callback_lock);
 out_unlock:
        mutex_unlock(&cpuset_mutex);
index f04daabfd1cffb78856e03b634b9d7c914faf4d1..2fabc062716591e960dbab2c9cfc16a755895773 100644 (file)
@@ -3591,7 +3591,7 @@ static void put_event(struct perf_event *event)
        ctx = perf_event_ctx_lock_nested(event, SINGLE_DEPTH_NESTING);
        WARN_ON_ONCE(ctx->parent_ctx);
        perf_remove_from_context(event, true);
-       mutex_unlock(&ctx->mutex);
+       perf_event_ctx_unlock(event, ctx);
 
        _free_event(event);
 }
@@ -4574,6 +4574,13 @@ static void perf_pending_event(struct irq_work *entry)
 {
        struct perf_event *event = container_of(entry,
                        struct perf_event, pending);
+       int rctx;
+
+       rctx = perf_swevent_get_recursion_context();
+       /*
+        * If we 'fail' here, that's OK, it means recursion is already disabled
+        * and we won't recurse 'further'.
+        */
 
        if (event->pending_disable) {
                event->pending_disable = 0;
@@ -4584,6 +4591,9 @@ static void perf_pending_event(struct irq_work *entry)
                event->pending_wakeup = 0;
                perf_event_wakeup(event);
        }
+
+       if (rctx >= 0)
+               perf_swevent_put_recursion_context(rctx);
 }
 
 /*
index 196a06fbc122fed81333c3bfd7205cfcef9aa73f..886d09e691d5a8d180826f2d5581c6bfb252d63c 100644 (file)
@@ -1474,8 +1474,13 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
         * otherwise we'll have trouble later trying to figure out
         * which interrupt is which (messes up the interrupt freeing
         * logic etc).
+        *
+        * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and
+        * it cannot be set along with IRQF_NO_SUSPEND.
         */
-       if ((irqflags & IRQF_SHARED) && !dev_id)
+       if (((irqflags & IRQF_SHARED) && !dev_id) ||
+           (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||
+           ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))
                return -EINVAL;
 
        desc = irq_to_desc(irq);
index 3ca5325927045572edfa7d3eebd79f01b2a4c29a..5204a6d1b9854feecfc2fff678e1d2b8eef33c42 100644 (file)
@@ -43,9 +43,12 @@ void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action)
 
        if (action->flags & IRQF_NO_SUSPEND)
                desc->no_suspend_depth++;
+       else if (action->flags & IRQF_COND_SUSPEND)
+               desc->cond_suspend_depth++;
 
        WARN_ON_ONCE(desc->no_suspend_depth &&
-                    desc->no_suspend_depth != desc->nr_actions);
+                    (desc->no_suspend_depth +
+                       desc->cond_suspend_depth) != desc->nr_actions);
 }
 
 /*
@@ -61,6 +64,8 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action)
 
        if (action->flags & IRQF_NO_SUSPEND)
                desc->no_suspend_depth--;
+       else if (action->flags & IRQF_COND_SUSPEND)
+               desc->cond_suspend_depth--;
 }
 
 static bool suspend_device_irq(struct irq_desc *desc, int irq)
index ff7f47d026ac48b21d6239f9db36ee8662585a45..3f9f1d6b4c2e5726217556a40454c46dbe368b89 100644 (file)
@@ -89,16 +89,28 @@ static bool klp_is_object_loaded(struct klp_object *obj)
 /* sets obj->mod if object is not vmlinux and module is found */
 static void klp_find_object_module(struct klp_object *obj)
 {
+       struct module *mod;
+
        if (!klp_is_module(obj))
                return;
 
        mutex_lock(&module_mutex);
        /*
-        * We don't need to take a reference on the module here because we have
-        * the klp_mutex, which is also taken by the module notifier.  This
-        * prevents any module from unloading until we release the klp_mutex.
+        * We do not want to block removal of patched modules and therefore
+        * we do not take a reference here. The patches are removed by
+        * a going module handler instead.
+        */
+       mod = find_module(obj->name);
+       /*
+        * Do not mess work of the module coming and going notifiers.
+        * Note that the patch might still be needed before the going handler
+        * is called. Module functions can be called even in the GOING state
+        * until mod->exit() finishes. This is especially important for
+        * patches that modify semantic of the functions.
         */
-       obj->mod = find_module(obj->name);
+       if (mod && mod->klp_alive)
+               obj->mod = mod;
+
        mutex_unlock(&module_mutex);
 }
 
@@ -248,11 +260,12 @@ static int klp_find_external_symbol(struct module *pmod, const char *name,
        /* first, check if it's an exported symbol */
        preempt_disable();
        sym = find_symbol(name, NULL, NULL, true, true);
-       preempt_enable();
        if (sym) {
                *addr = sym->value;
+               preempt_enable();
                return 0;
        }
+       preempt_enable();
 
        /* otherwise check if it's in another .o within the patch module */
        return klp_find_object_symbol(pmod->name, name, addr);
@@ -314,12 +327,12 @@ static void notrace klp_ftrace_handler(unsigned long ip,
        rcu_read_lock();
        func = list_first_or_null_rcu(&ops->func_stack, struct klp_func,
                                      stack_node);
-       rcu_read_unlock();
-
        if (WARN_ON_ONCE(!func))
-               return;
+               goto unlock;
 
        klp_arch_set_pc(regs, (unsigned long)func->new_func);
+unlock:
+       rcu_read_unlock();
 }
 
 static int klp_disable_func(struct klp_func *func)
@@ -731,7 +744,7 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
        func->state = KLP_DISABLED;
 
        return kobject_init_and_add(&func->kobj, &klp_ktype_func,
-                                   obj->kobj, func->old_name);
+                                   obj->kobj, "%s", func->old_name);
 }
 
 /* parts of the initialization that is done only when the object is loaded */
@@ -766,6 +779,7 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
                return -EINVAL;
 
        obj->state = KLP_DISABLED;
+       obj->mod = NULL;
 
        klp_find_object_module(obj);
 
@@ -807,7 +821,7 @@ static int klp_init_patch(struct klp_patch *patch)
        patch->state = KLP_DISABLED;
 
        ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch,
-                                  klp_root_kobj, patch->mod->name);
+                                  klp_root_kobj, "%s", patch->mod->name);
        if (ret)
                goto unlock;
 
@@ -960,6 +974,15 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action,
 
        mutex_lock(&klp_mutex);
 
+       /*
+        * Each module has to know that the notifier has been called.
+        * We never know what module will get patched by a new patch.
+        */
+       if (action == MODULE_STATE_COMING)
+               mod->klp_alive = true;
+       else /* MODULE_STATE_GOING */
+               mod->klp_alive = false;
+
        list_for_each_entry(patch, &klp_patches, list) {
                for (obj = patch->objs; obj->funcs; obj++) {
                        if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
index 88d0d4420ad2e3e47e71129d361b153c96a49e18..ba77ab5f64dd9809f5e24f1b079ac5abbefeb495 100644 (file)
@@ -633,7 +633,7 @@ static int count_matching_names(struct lock_class *new_class)
        if (!new_class->name)
                return 0;
 
-       list_for_each_entry(class, &all_lock_classes, lock_entry) {
+       list_for_each_entry_rcu(class, &all_lock_classes, lock_entry) {
                if (new_class->key - new_class->subclass == class->key)
                        return class->name_version;
                if (class->name && !strcmp(class->name, new_class->name))
@@ -700,10 +700,12 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
        hash_head = classhashentry(key);
 
        /*
-        * We can walk the hash lockfree, because the hash only
-        * grows, and we are careful when adding entries to the end:
+        * We do an RCU walk of the hash, see lockdep_free_key_range().
         */
-       list_for_each_entry(class, hash_head, hash_entry) {
+       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+               return NULL;
+
+       list_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key) {
                        /*
                         * Huh! same key, different name? Did someone trample
@@ -728,7 +730,8 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        struct lockdep_subclass_key *key;
        struct list_head *hash_head;
        struct lock_class *class;
-       unsigned long flags;
+
+       DEBUG_LOCKS_WARN_ON(!irqs_disabled());
 
        class = look_up_lock_class(lock, subclass);
        if (likely(class))
@@ -750,28 +753,26 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        key = lock->key->subkeys + subclass;
        hash_head = classhashentry(key);
 
-       raw_local_irq_save(flags);
        if (!graph_lock()) {
-               raw_local_irq_restore(flags);
                return NULL;
        }
        /*
         * We have to do the hash-walk again, to avoid races
         * with another CPU:
         */
-       list_for_each_entry(class, hash_head, hash_entry)
+       list_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key)
                        goto out_unlock_set;
+       }
+
        /*
         * Allocate a new key from the static array, and add it to
         * the hash:
         */
        if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
                if (!debug_locks_off_graph_unlock()) {
-                       raw_local_irq_restore(flags);
                        return NULL;
                }
-               raw_local_irq_restore(flags);
 
                print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!");
                dump_stack();
@@ -798,7 +799,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
 
        if (verbose(class)) {
                graph_unlock();
-               raw_local_irq_restore(flags);
 
                printk("\nnew class %p: %s", class->key, class->name);
                if (class->name_version > 1)
@@ -806,15 +806,12 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
                printk("\n");
                dump_stack();
 
-               raw_local_irq_save(flags);
                if (!graph_lock()) {
-                       raw_local_irq_restore(flags);
                        return NULL;
                }
        }
 out_unlock_set:
        graph_unlock();
-       raw_local_irq_restore(flags);
 
 out_set_class_cache:
        if (!subclass || force)
@@ -870,11 +867,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
        entry->distance = distance;
        entry->trace = *trace;
        /*
-        * Since we never remove from the dependency list, the list can
-        * be walked lockless by other CPUs, it's only allocation
-        * that must be protected by the spinlock. But this also means
-        * we must make new entries visible only once writes to the
-        * entry become visible - hence the RCU op:
+        * Both allocation and removal are done under the graph lock; but
+        * iteration is under RCU-sched; see look_up_lock_class() and
+        * lockdep_free_key_range().
         */
        list_add_tail_rcu(&entry->entry, head);
 
@@ -1025,7 +1020,9 @@ static int __bfs(struct lock_list *source_entry,
                else
                        head = &lock->class->locks_before;
 
-               list_for_each_entry(entry, head, entry) {
+               DEBUG_LOCKS_WARN_ON(!irqs_disabled());
+
+               list_for_each_entry_rcu(entry, head, entry) {
                        if (!lock_accessed(entry)) {
                                unsigned int cq_depth;
                                mark_lock_accessed(entry, lock);
@@ -2022,7 +2019,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
         * We can walk it lock-free, because entries only get added
         * to the hash:
         */
-       list_for_each_entry(chain, hash_head, entry) {
+       list_for_each_entry_rcu(chain, hash_head, entry) {
                if (chain->chain_key == chain_key) {
 cache_hit:
                        debug_atomic_inc(chain_lookup_hits);
@@ -2996,8 +2993,18 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
        if (unlikely(!debug_locks))
                return;
 
-       if (subclass)
+       if (subclass) {
+               unsigned long flags;
+
+               if (DEBUG_LOCKS_WARN_ON(current->lockdep_recursion))
+                       return;
+
+               raw_local_irq_save(flags);
+               current->lockdep_recursion = 1;
                register_lock_class(lock, subclass, 1);
+               current->lockdep_recursion = 0;
+               raw_local_irq_restore(flags);
+       }
 }
 EXPORT_SYMBOL_GPL(lockdep_init_map);
 
@@ -3887,9 +3894,17 @@ static inline int within(const void *addr, void *start, unsigned long size)
        return addr >= start && addr < start + size;
 }
 
+/*
+ * Used in module.c to remove lock classes from memory that is going to be
+ * freed; and possibly re-used by other modules.
+ *
+ * We will have had one sync_sched() before getting here, so we're guaranteed
+ * nobody will look up these exact classes -- they're properly dead but still
+ * allocated.
+ */
 void lockdep_free_key_range(void *start, unsigned long size)
 {
-       struct lock_class *class, *next;
+       struct lock_class *class;
        struct list_head *head;
        unsigned long flags;
        int i;
@@ -3905,7 +3920,7 @@ void lockdep_free_key_range(void *start, unsigned long size)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry) {
+               list_for_each_entry_rcu(class, head, hash_entry) {
                        if (within(class->key, start, size))
                                zap_class(class);
                        else if (within(class->name, start, size))
@@ -3916,11 +3931,25 @@ void lockdep_free_key_range(void *start, unsigned long size)
        if (locked)
                graph_unlock();
        raw_local_irq_restore(flags);
+
+       /*
+        * Wait for any possible iterators from look_up_lock_class() to pass
+        * before continuing to free the memory they refer to.
+        *
+        * sync_sched() is sufficient because the read-side is IRQ disable.
+        */
+       synchronize_sched();
+
+       /*
+        * XXX at this point we could return the resources to the pool;
+        * instead we leak them. We would need to change to bitmap allocators
+        * instead of the linear allocators we have now.
+        */
 }
 
 void lockdep_reset_lock(struct lockdep_map *lock)
 {
-       struct lock_class *class, *next;
+       struct lock_class *class;
        struct list_head *head;
        unsigned long flags;
        int i, j;
@@ -3948,7 +3977,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
                head = classhash_table + i;
                if (list_empty(head))
                        continue;
-               list_for_each_entry_safe(class, next, head, hash_entry) {
+               list_for_each_entry_rcu(class, head, hash_entry) {
                        int match = 0;
 
                        for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++)
index e16e5542bf13f381a36c304b7e6b1ff9b66aaea0..6357265a31ad1a34b881aba31abe27ab6d3921ec 100644 (file)
@@ -1193,6 +1193,7 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
                ret = __rt_mutex_slowlock(lock, state, timeout, &waiter);
 
        if (unlikely(ret)) {
+               __set_current_state(TASK_RUNNING);
                if (rt_mutex_has_waiters(lock))
                        remove_waiter(lock, &waiter);
                rt_mutex_handle_deadlock(ret, chwalk, &waiter);
index b34813f725e970fa79b97e625fab6c568543aaf8..99fdf94efce80f432fc4ab203aeb2a918ad5c564 100644 (file)
@@ -56,7 +56,6 @@
 #include <linux/async.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
-#include <linux/kasan.h>
 #include <linux/jump_label.h>
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
@@ -1814,7 +1813,6 @@ static void unset_module_init_ro_nx(struct module *mod) { }
 void __weak module_memfree(void *module_region)
 {
        vfree(module_region);
-       kasan_module_free(module_region);
 }
 
 void __weak module_arch_cleanup(struct module *mod)
@@ -1867,7 +1865,7 @@ static void free_module(struct module *mod)
        kfree(mod->args);
        percpu_modfree(mod);
 
-       /* Free lock-classes: */
+       /* Free lock-classes; relies on the preceding sync_rcu(). */
        lockdep_free_key_range(mod->module_core, mod->core_size);
 
        /* Finally, free the core (containing the module structure) */
@@ -2313,11 +2311,13 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
        info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
        mod->core_size += strtab_size;
+       mod->core_size = debug_align(mod->core_size);
 
        /* Put string table section at end of init part of module. */
        strsect->sh_flags |= SHF_ALLOC;
        strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
                                         info->index.str) | INIT_OFFSET_MASK;
+       mod->init_size = debug_align(mod->init_size);
        pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
 }
 
@@ -3349,9 +3349,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
        module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
 
-       /* Free lock-classes: */
-       lockdep_free_key_range(mod->module_core, mod->core_size);
-
        /* we can't deallocate the module until we clear memory protection */
        unset_module_init_ro_nx(mod);
        unset_module_core_ro_nx(mod);
@@ -3375,6 +3372,9 @@ static int load_module(struct load_info *info, const char __user *uargs,
        synchronize_rcu();
        mutex_unlock(&module_mutex);
  free_module:
+       /* Free lock-classes; relies on the preceding sync_rcu() */
+       lockdep_free_key_range(mod->module_core, mod->core_size);
+
        module_deallocate(mod, info);
  free_copy:
        free_copy(info);
index cbd69d842341175e4c6db7c68a4b6e3689f5c928..2ca4a8b5fe57960c584d74e7dabf76b22bc71613 100644 (file)
@@ -3,7 +3,7 @@
 
 struct console_cmdline
 {
-       char    name[8];                        /* Name of the driver       */
+       char    name[16];                       /* Name of the driver       */
        int     index;                          /* Minor dev. to use        */
        char    *options;                       /* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
index 01cfd69c54c6772ad49a1d81120258f765f435a1..bb0635bd74f26a2ecb9f651de9e0c4113e4f2476 100644 (file)
@@ -2464,6 +2464,7 @@ void register_console(struct console *newcon)
        for (i = 0, c = console_cmdline;
             i < MAX_CMDLINECONSOLES && c->name[0];
             i++, c++) {
+               BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
                if (strcmp(c->name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
index f0f831e8a345d835f4cb21bf899c50ab67042b43..62671f53202ac7d4de8037dce950c934c7a4ddbc 100644 (file)
@@ -3034,6 +3034,8 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        } else {
                if (dl_prio(oldprio))
                        p->dl.dl_boosted = 0;
+               if (rt_prio(oldprio))
+                       p->rt.timeout = 0;
                p->sched_class = &fair_sched_class;
        }
 
index 7ce18f3c097ac4779eb4cf6ed0ad14ac1beb3eb5..bcfe32088b3768363c2f37502a953b61a361f7ff 100644 (file)
@@ -1609,9 +1609,11 @@ static void update_task_scan_period(struct task_struct *p,
        /*
         * If there were no record hinting faults then either the task is
         * completely idle or all activity is areas that are not of interest
-        * to automatic numa balancing. Scan slower
+        * to automatic numa balancing. Related to that, if there were failed
+        * migration then it implies we are migrating too quickly or the local
+        * node is overloaded. In either case, scan slower
         */
-       if (local + shared == 0) {
+       if (local + shared == 0 || p->numa_faults_locality[2]) {
                p->numa_scan_period = min(p->numa_scan_period_max,
                        p->numa_scan_period << 1);
 
@@ -2080,6 +2082,8 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
 
        if (migrated)
                p->numa_pages_migrated += pages;
+       if (flags & TNF_MIGRATE_FAIL)
+               p->numa_faults_locality[2] += pages;
 
        p->numa_faults[task_faults_idx(NUMA_MEMBUF, mem_node, priv)] += pages;
        p->numa_faults[task_faults_idx(NUMA_CPUBUF, cpu_node, priv)] += pages;
index 94b2d7b88a272856bf0f49ac0f0bdce430a5255d..80014a17834214fcad51add08b2b171463e84128 100644 (file)
@@ -82,6 +82,7 @@ static void cpuidle_idle_call(void)
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int next_state, entered_state;
        unsigned int broadcast;
+       bool reflect;
 
        /*
         * Check if the idle task must be rescheduled. If it is the
@@ -105,6 +106,9 @@ static void cpuidle_idle_call(void)
         */
        rcu_idle_enter();
 
+       if (cpuidle_not_available(drv, dev))
+               goto use_default;
+
        /*
         * Suspend-to-idle ("freeze") is a system state in which all user space
         * has been frozen, all I/O devices have been suspended and the only
@@ -115,30 +119,24 @@ static void cpuidle_idle_call(void)
         * until a proper wakeup interrupt happens.
         */
        if (idle_should_freeze()) {
-               cpuidle_enter_freeze();
-               local_irq_enable();
-               goto exit_idle;
-       }
+               entered_state = cpuidle_enter_freeze(drv, dev);
+               if (entered_state >= 0) {
+                       local_irq_enable();
+                       goto exit_idle;
+               }
 
-       /*
-        * Ask the cpuidle framework to choose a convenient idle state.
-        * Fall back to the default arch idle method on errors.
-        */
-       next_state = cpuidle_select(drv, dev);
-       if (next_state < 0) {
-use_default:
+               reflect = false;
+               next_state = cpuidle_find_deepest_state(drv, dev);
+       } else {
+               reflect = true;
                /*
-                * We can't use the cpuidle framework, let's use the default
-                * idle routine.
+                * Ask the cpuidle framework to choose a convenient idle state.
                 */
-               if (current_clr_polling_and_test())
-                       local_irq_enable();
-               else
-                       arch_cpu_idle();
-
-               goto exit_idle;
+               next_state = cpuidle_select(drv, dev);
        }
-
+       /* Fall back to the default arch idle method on errors. */
+       if (next_state < 0)
+               goto use_default;
 
        /*
         * The idle task must be scheduled, it is pointless to
@@ -183,7 +181,8 @@ use_default:
        /*
         * Give the governor an opportunity to reflect on the outcome
         */
-       cpuidle_reflect(dev, entered_state);
+       if (reflect)
+               cpuidle_reflect(dev, entered_state);
 
 exit_idle:
        __current_set_polling();
@@ -196,6 +195,19 @@ exit_idle:
 
        rcu_idle_exit();
        start_critical_timings();
+       return;
+
+use_default:
+       /*
+        * We can't use the cpuidle framework, let's use the default
+        * idle routine.
+        */
+       if (current_clr_polling_and_test())
+               local_irq_enable();
+       else
+               arch_cpu_idle();
+
+       goto exit_idle;
 }
 
 /*
index 667b2e62fad25bffd03109b4468fd3cbd4af00bf..a03d9cd23ed779b2a38d8bf564bac6860d934f2f 100644 (file)
@@ -1108,6 +1108,7 @@ DECLARE_RWSEM(uts_sem);
 /*
  * Work around broken programs that cannot handle "Linux 3.0".
  * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
+ * And we map 4.x to 2.6.60+x, so 4.0 would be 2.6.60.
  */
 static int override_release(char __user *release, size_t len)
 {
@@ -1127,7 +1128,7 @@ static int override_release(char __user *release, size_t len)
                                break;
                        rest++;
                }
-               v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
+               v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 60;
                copy = clamp_t(size_t, len, 1, sizeof(buf));
                copy = scnprintf(buf, copy, "2.6.%u%s", v, rest);
                ret = copy_to_user(release, buf, copy + 1);
index 88ea2d6e00314059b96adb0505ffc5f9c98fcf73..ce410bb9f2e103e0fcfda7d7b844948a0a28fbce 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 eb682d5c697cd5b67c988654915d1f5333fbe342..6aac4beedbbe235951c0671336e52b2459a047fb 100644 (file)
@@ -49,6 +49,7 @@ static void bc_set_mode(enum clock_event_mode mode,
  */
 static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
 {
+       int bc_moved;
        /*
         * We try to cancel the timer first. If the callback is on
         * flight on some other cpu then we let it handle it. If we
@@ -60,9 +61,15 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
         * restart the timer because we are in the callback, but we
         * can set the expiry time and let the callback return
         * HRTIMER_RESTART.
+        *
+        * Since we are in the idle loop at this point and because
+        * hrtimer_{start/cancel} functions call into tracing,
+        * calls to these functions must be bound within RCU_NONIDLE.
         */
-       if (hrtimer_try_to_cancel(&bctimer) >= 0) {
-               hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED);
+       RCU_NONIDLE(bc_moved = (hrtimer_try_to_cancel(&bctimer) >= 0) ?
+               !hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED) :
+                       0);
+       if (bc_moved) {
                /* Bind the "device" to the cpu */
                bc->bound_on = smp_processor_id();
        } else if (bc->bound_on == smp_processor_id()) {
index 45e5cb143d173d979576689dbc8e7a66703eee06..4f228024055b119d93279705ec4c42d7475c72f7 100644 (file)
@@ -1059,6 +1059,12 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
 
 static struct pid * const ftrace_swapper_pid = &init_struct_pid;
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static int ftrace_graph_active;
+#else
+# define ftrace_graph_active 0
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 static struct ftrace_ops *removed_ops;
@@ -2041,8 +2047,12 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
                if (!ftrace_rec_count(rec))
                        rec->flags = 0;
                else
-                       /* Just disable the record (keep REGS state) */
-                       rec->flags &= ~FTRACE_FL_ENABLED;
+                       /*
+                        * Just disable the record, but keep the ops TRAMP
+                        * and REGS states. The _EN flags must be disabled though.
+                        */
+                       rec->flags &= ~(FTRACE_FL_ENABLED | FTRACE_FL_TRAMP_EN |
+                                       FTRACE_FL_REGS_EN);
        }
 
        return FTRACE_UPDATE_MAKE_NOP;
@@ -2688,24 +2698,36 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
 
 static void ftrace_startup_sysctl(void)
 {
+       int command;
+
        if (unlikely(ftrace_disabled))
                return;
 
        /* Force update next time */
        saved_ftrace_func = NULL;
        /* ftrace_start_up is true if we want ftrace running */
-       if (ftrace_start_up)
-               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+       if (ftrace_start_up) {
+               command = FTRACE_UPDATE_CALLS;
+               if (ftrace_graph_active)
+                       command |= FTRACE_START_FUNC_RET;
+               ftrace_startup_enable(command);
+       }
 }
 
 static void ftrace_shutdown_sysctl(void)
 {
+       int command;
+
        if (unlikely(ftrace_disabled))
                return;
 
        /* ftrace_start_up is true if ftrace is running */
-       if (ftrace_start_up)
-               ftrace_run_update_code(FTRACE_DISABLE_CALLS);
+       if (ftrace_start_up) {
+               command = FTRACE_DISABLE_CALLS;
+               if (ftrace_graph_active)
+                       command |= FTRACE_STOP_FUNC_RET;
+               ftrace_run_update_code(command);
+       }
 }
 
 static cycle_t         ftrace_update_time;
@@ -5558,12 +5580,12 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 
        if (ftrace_enabled) {
 
-               ftrace_startup_sysctl();
-
                /* we are starting ftrace again */
                if (ftrace_ops_list != &ftrace_list_end)
                        update_ftrace_function();
 
+               ftrace_startup_sysctl();
+
        } else {
                /* stopping ftrace calls (just send to ftrace_stub) */
                ftrace_trace_function = ftrace_stub;
@@ -5590,8 +5612,6 @@ static struct ftrace_ops graph_ops = {
        ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)
 };
 
-static int ftrace_graph_active;
-
 int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
 {
        return 0;
index f2884939479109f349b6291a82ee4cc990aa1c32..41ff75b478c60b443cd80626351b1e3f3030f94b 100644 (file)
@@ -2728,19 +2728,57 @@ bool flush_work(struct work_struct *work)
 }
 EXPORT_SYMBOL_GPL(flush_work);
 
+struct cwt_wait {
+       wait_queue_t            wait;
+       struct work_struct      *work;
+};
+
+static int cwt_wakefn(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+       struct cwt_wait *cwait = container_of(wait, struct cwt_wait, wait);
+
+       if (cwait->work != key)
+               return 0;
+       return autoremove_wake_function(wait, mode, sync, key);
+}
+
 static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
 {
+       static DECLARE_WAIT_QUEUE_HEAD(cancel_waitq);
        unsigned long flags;
        int ret;
 
        do {
                ret = try_to_grab_pending(work, is_dwork, &flags);
                /*
-                * If someone else is canceling, wait for the same event it
-                * would be waiting for before retrying.
+                * If someone else is already canceling, wait for it to
+                * finish.  flush_work() doesn't work for PREEMPT_NONE
+                * because we may get scheduled between @work's completion
+                * and the other canceling task resuming and clearing
+                * CANCELING - flush_work() will return false immediately
+                * as @work is no longer busy, try_to_grab_pending() will
+                * return -ENOENT as @work is still being canceled and the
+                * other canceling task won't be able to clear CANCELING as
+                * we're hogging the CPU.
+                *
+                * Let's wait for completion using a waitqueue.  As this
+                * may lead to the thundering herd problem, use a custom
+                * wake function which matches @work along with exclusive
+                * wait and wakeup.
                 */
-               if (unlikely(ret == -ENOENT))
-                       flush_work(work);
+               if (unlikely(ret == -ENOENT)) {
+                       struct cwt_wait cwait;
+
+                       init_wait(&cwait.wait);
+                       cwait.wait.func = cwt_wakefn;
+                       cwait.work = work;
+
+                       prepare_to_wait_exclusive(&cancel_waitq, &cwait.wait,
+                                                 TASK_UNINTERRUPTIBLE);
+                       if (work_is_canceling(work))
+                               schedule();
+                       finish_wait(&cancel_waitq, &cwait.wait);
+               }
        } while (unlikely(ret < 0));
 
        /* tell other tasks trying to grab @work to back off */
@@ -2749,6 +2787,16 @@ static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
 
        flush_work(work);
        clear_work_data(work);
+
+       /*
+        * Paired with prepare_to_wait() above so that either
+        * waitqueue_active() is visible here or !work_is_canceling() is
+        * visible there.
+        */
+       smp_mb();
+       if (waitqueue_active(&cancel_waitq))
+               __wake_up(&cancel_waitq, TASK_NORMAL, 1, work);
+
        return ret;
 }
 
index 87eb3bffc283aa8c0e65c5678729dbad484bd5bf..58f74d2dd3967a3bf0a6d9f5dc9996bfeb9bc842 100644 (file)
@@ -24,7 +24,7 @@ obj-y += lockref.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
-        gcd.o lcm.o list_sort.o uuid.o flex_array.o clz_ctz.o \
+        gcd.o lcm.o list_sort.o uuid.o flex_array.o iov_iter.o clz_ctz.o \
         bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
         percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o
 obj-y += string_helpers.o
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
new file mode 100644 (file)
index 0000000..9d96e28
--- /dev/null
@@ -0,0 +1,768 @@
+#include <linux/export.h>
+#include <linux/uio.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <net/checksum.h>
+
+#define iterate_iovec(i, n, __v, __p, skip, STEP) {    \
+       size_t left;                                    \
+       size_t wanted = n;                              \
+       __p = i->iov;                                   \
+       __v.iov_len = min(n, __p->iov_len - skip);      \
+       if (likely(__v.iov_len)) {                      \
+               __v.iov_base = __p->iov_base + skip;    \
+               left = (STEP);                          \
+               __v.iov_len -= left;                    \
+               skip += __v.iov_len;                    \
+               n -= __v.iov_len;                       \
+       } else {                                        \
+               left = 0;                               \
+       }                                               \
+       while (unlikely(!left && n)) {                  \
+               __p++;                                  \
+               __v.iov_len = min(n, __p->iov_len);     \
+               if (unlikely(!__v.iov_len))             \
+                       continue;                       \
+               __v.iov_base = __p->iov_base;           \
+               left = (STEP);                          \
+               __v.iov_len -= left;                    \
+               skip = __v.iov_len;                     \
+               n -= __v.iov_len;                       \
+       }                                               \
+       n = wanted - n;                                 \
+}
+
+#define iterate_kvec(i, n, __v, __p, skip, STEP) {     \
+       size_t wanted = n;                              \
+       __p = i->kvec;                                  \
+       __v.iov_len = min(n, __p->iov_len - skip);      \
+       if (likely(__v.iov_len)) {                      \
+               __v.iov_base = __p->iov_base + skip;    \
+               (void)(STEP);                           \
+               skip += __v.iov_len;                    \
+               n -= __v.iov_len;                       \
+       }                                               \
+       while (unlikely(n)) {                           \
+               __p++;                                  \
+               __v.iov_len = min(n, __p->iov_len);     \
+               if (unlikely(!__v.iov_len))             \
+                       continue;                       \
+               __v.iov_base = __p->iov_base;           \
+               (void)(STEP);                           \
+               skip = __v.iov_len;                     \
+               n -= __v.iov_len;                       \
+       }                                               \
+       n = wanted;                                     \
+}
+
+#define iterate_bvec(i, n, __v, __p, skip, STEP) {     \
+       size_t wanted = n;                              \
+       __p = i->bvec;                                  \
+       __v.bv_len = min_t(size_t, n, __p->bv_len - skip);      \
+       if (likely(__v.bv_len)) {                       \
+               __v.bv_page = __p->bv_page;             \
+               __v.bv_offset = __p->bv_offset + skip;  \
+               (void)(STEP);                           \
+               skip += __v.bv_len;                     \
+               n -= __v.bv_len;                        \
+       }                                               \
+       while (unlikely(n)) {                           \
+               __p++;                                  \
+               __v.bv_len = min_t(size_t, n, __p->bv_len);     \
+               if (unlikely(!__v.bv_len))              \
+                       continue;                       \
+               __v.bv_page = __p->bv_page;             \
+               __v.bv_offset = __p->bv_offset;         \
+               (void)(STEP);                           \
+               skip = __v.bv_len;                      \
+               n -= __v.bv_len;                        \
+       }                                               \
+       n = wanted;                                     \
+}
+
+#define iterate_all_kinds(i, n, v, I, B, K) {                  \
+       size_t skip = i->iov_offset;                            \
+       if (unlikely(i->type & ITER_BVEC)) {                    \
+               const struct bio_vec *bvec;                     \
+               struct bio_vec v;                               \
+               iterate_bvec(i, n, v, bvec, skip, (B))          \
+       } else if (unlikely(i->type & ITER_KVEC)) {             \
+               const struct kvec *kvec;                        \
+               struct kvec v;                                  \
+               iterate_kvec(i, n, v, kvec, skip, (K))          \
+       } else {                                                \
+               const struct iovec *iov;                        \
+               struct iovec v;                                 \
+               iterate_iovec(i, n, v, iov, skip, (I))          \
+       }                                                       \
+}
+
+#define iterate_and_advance(i, n, v, I, B, K) {                        \
+       size_t skip = i->iov_offset;                            \
+       if (unlikely(i->type & ITER_BVEC)) {                    \
+               const struct bio_vec *bvec;                     \
+               struct bio_vec v;                               \
+               iterate_bvec(i, n, v, bvec, skip, (B))          \
+               if (skip == bvec->bv_len) {                     \
+                       bvec++;                                 \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= bvec - i->bvec;                   \
+               i->bvec = bvec;                                 \
+       } else if (unlikely(i->type & ITER_KVEC)) {             \
+               const struct kvec *kvec;                        \
+               struct kvec v;                                  \
+               iterate_kvec(i, n, v, kvec, skip, (K))          \
+               if (skip == kvec->iov_len) {                    \
+                       kvec++;                                 \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= kvec - i->kvec;                   \
+               i->kvec = kvec;                                 \
+       } else {                                                \
+               const struct iovec *iov;                        \
+               struct iovec v;                                 \
+               iterate_iovec(i, n, v, iov, skip, (I))          \
+               if (skip == iov->iov_len) {                     \
+                       iov++;                                  \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= iov - i->iov;                     \
+               i->iov = iov;                                   \
+       }                                                       \
+       i->count -= n;                                          \
+       i->iov_offset = skip;                                   \
+}
+
+static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+       void *kaddr, *from;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       if (!fault_in_pages_writeable(buf, copy)) {
+               kaddr = kmap_atomic(page);
+               from = kaddr + offset;
+
+               /* first chunk, usually the only one */
+               left = __copy_to_user_inatomic(buf, from, copy);
+               copy -= left;
+               skip += copy;
+               from += copy;
+               bytes -= copy;
+
+               while (unlikely(!left && bytes)) {
+                       iov++;
+                       buf = iov->iov_base;
+                       copy = min(bytes, iov->iov_len);
+                       left = __copy_to_user_inatomic(buf, from, copy);
+                       copy -= left;
+                       skip = copy;
+                       from += copy;
+                       bytes -= copy;
+               }
+               if (likely(!bytes)) {
+                       kunmap_atomic(kaddr);
+                       goto done;
+               }
+               offset = from - kaddr;
+               buf += copy;
+               kunmap_atomic(kaddr);
+               copy = min(bytes, iov->iov_len - skip);
+       }
+       /* Too bad - revert to non-atomic kmap */
+       kaddr = kmap(page);
+       from = kaddr + offset;
+       left = __copy_to_user(buf, from, copy);
+       copy -= left;
+       skip += copy;
+       from += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_to_user(buf, from, copy);
+               copy -= left;
+               skip = copy;
+               from += copy;
+               bytes -= copy;
+       }
+       kunmap(page);
+done:
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+       void *kaddr, *to;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       if (!fault_in_pages_readable(buf, copy)) {
+               kaddr = kmap_atomic(page);
+               to = kaddr + offset;
+
+               /* first chunk, usually the only one */
+               left = __copy_from_user_inatomic(to, buf, copy);
+               copy -= left;
+               skip += copy;
+               to += copy;
+               bytes -= copy;
+
+               while (unlikely(!left && bytes)) {
+                       iov++;
+                       buf = iov->iov_base;
+                       copy = min(bytes, iov->iov_len);
+                       left = __copy_from_user_inatomic(to, buf, copy);
+                       copy -= left;
+                       skip = copy;
+                       to += copy;
+                       bytes -= copy;
+               }
+               if (likely(!bytes)) {
+                       kunmap_atomic(kaddr);
+                       goto done;
+               }
+               offset = to - kaddr;
+               buf += copy;
+               kunmap_atomic(kaddr);
+               copy = min(bytes, iov->iov_len - skip);
+       }
+       /* Too bad - revert to non-atomic kmap */
+       kaddr = kmap(page);
+       to = kaddr + offset;
+       left = __copy_from_user(to, buf, copy);
+       copy -= left;
+       skip += copy;
+       to += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_from_user(to, buf, copy);
+               copy -= left;
+               skip = copy;
+               to += copy;
+               bytes -= copy;
+       }
+       kunmap(page);
+done:
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+/*
+ * Fault in the first iovec of the given iov_iter, to a maximum length
+ * of bytes. Returns 0 on success, or non-zero if the memory could not be
+ * accessed (ie. because it is an invalid address).
+ *
+ * writev-intensive code may want this to prefault several iovecs -- that
+ * would be possible (callers must not rely on the fact that _only_ the
+ * first iovec will be faulted with the current implementation).
+ */
+int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
+{
+       if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
+               char __user *buf = i->iov->iov_base + i->iov_offset;
+               bytes = min(bytes, i->iov->iov_len - i->iov_offset);
+               return fault_in_pages_readable(buf, bytes);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_fault_in_readable);
+
+void iov_iter_init(struct iov_iter *i, int direction,
+                       const struct iovec *iov, unsigned long nr_segs,
+                       size_t count)
+{
+       /* It will get better.  Eventually... */
+       if (segment_eq(get_fs(), KERNEL_DS)) {
+               direction |= ITER_KVEC;
+               i->type = direction;
+               i->kvec = (struct kvec *)iov;
+       } else {
+               i->type = direction;
+               i->iov = iov;
+       }
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_init);
+
+static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
+{
+       char *from = kmap_atomic(page);
+       memcpy(to, from + offset, len);
+       kunmap_atomic(from);
+}
+
+static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len)
+{
+       char *to = kmap_atomic(page);
+       memcpy(to + offset, from, len);
+       kunmap_atomic(to);
+}
+
+static void memzero_page(struct page *page, size_t offset, size_t len)
+{
+       char *addr = kmap_atomic(page);
+       memset(addr + offset, 0, len);
+       kunmap_atomic(addr);
+}
+
+size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *from = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len,
+                              v.iov_len),
+               memcpy_to_page(v.bv_page, v.bv_offset,
+                              (from += v.bv_len) - v.bv_len, v.bv_len),
+               memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_to_iter);
+
+size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *to = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base,
+                                v.iov_len),
+               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_from_iter);
+
+size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *to = addr;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __copy_from_user_nocache((to += v.iov_len) - v.iov_len,
+                                        v.iov_base, v.iov_len),
+               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(copy_from_iter_nocache);
+
+size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       if (i->type & (ITER_BVEC|ITER_KVEC)) {
+               void *kaddr = kmap_atomic(page);
+               size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
+               kunmap_atomic(kaddr);
+               return wanted;
+       } else
+               return copy_page_to_iter_iovec(page, offset, bytes, i);
+}
+EXPORT_SYMBOL(copy_page_to_iter);
+
+size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
+                        struct iov_iter *i)
+{
+       if (i->type & (ITER_BVEC|ITER_KVEC)) {
+               void *kaddr = kmap_atomic(page);
+               size_t wanted = copy_from_iter(kaddr + offset, bytes, i);
+               kunmap_atomic(kaddr);
+               return wanted;
+       } else
+               return copy_page_from_iter_iovec(page, offset, bytes, i);
+}
+EXPORT_SYMBOL(copy_page_from_iter);
+
+size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
+{
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       iterate_and_advance(i, bytes, v,
+               __clear_user(v.iov_base, v.iov_len),
+               memzero_page(v.bv_page, v.bv_offset, v.bv_len),
+               memset(v.iov_base, 0, v.iov_len)
+       )
+
+       return bytes;
+}
+EXPORT_SYMBOL(iov_iter_zero);
+
+size_t iov_iter_copy_from_user_atomic(struct page *page,
+               struct iov_iter *i, unsigned long offset, size_t bytes)
+{
+       char *kaddr = kmap_atomic(page), *p = kaddr + offset;
+       iterate_all_kinds(i, bytes, v,
+               __copy_from_user_inatomic((p += v.iov_len) - v.iov_len,
+                                         v.iov_base, v.iov_len),
+               memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+       kunmap_atomic(kaddr);
+       return bytes;
+}
+EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
+
+void iov_iter_advance(struct iov_iter *i, size_t size)
+{
+       iterate_and_advance(i, size, v, 0, 0, 0)
+}
+EXPORT_SYMBOL(iov_iter_advance);
+
+/*
+ * Return the count of just the current iov_iter segment.
+ */
+size_t iov_iter_single_seg_count(const struct iov_iter *i)
+{
+       if (i->nr_segs == 1)
+               return i->count;
+       else if (i->type & ITER_BVEC)
+               return min(i->count, i->bvec->bv_len - i->iov_offset);
+       else
+               return min(i->count, i->iov->iov_len - i->iov_offset);
+}
+EXPORT_SYMBOL(iov_iter_single_seg_count);
+
+void iov_iter_kvec(struct iov_iter *i, int direction,
+                       const struct kvec *kvec, unsigned long nr_segs,
+                       size_t count)
+{
+       BUG_ON(!(direction & ITER_KVEC));
+       i->type = direction;
+       i->kvec = kvec;
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_kvec);
+
+void iov_iter_bvec(struct iov_iter *i, int direction,
+                       const struct bio_vec *bvec, unsigned long nr_segs,
+                       size_t count)
+{
+       BUG_ON(!(direction & ITER_BVEC));
+       i->type = direction;
+       i->bvec = bvec;
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_bvec);
+
+unsigned long iov_iter_alignment(const struct iov_iter *i)
+{
+       unsigned long res = 0;
+       size_t size = i->count;
+
+       if (!size)
+               return 0;
+
+       iterate_all_kinds(i, size, v,
+               (res |= (unsigned long)v.iov_base | v.iov_len, 0),
+               res |= v.bv_offset | v.bv_len,
+               res |= (unsigned long)v.iov_base | v.iov_len
+       )
+       return res;
+}
+EXPORT_SYMBOL(iov_iter_alignment);
+
+ssize_t iov_iter_get_pages(struct iov_iter *i,
+                  struct page **pages, size_t maxsize, unsigned maxpages,
+                  size_t *start)
+{
+       if (maxsize > i->count)
+               maxsize = i->count;
+
+       if (!maxsize)
+               return 0;
+
+       iterate_all_kinds(i, maxsize, v, ({
+               unsigned long addr = (unsigned long)v.iov_base;
+               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
+               int n;
+               int res;
+
+               if (len > maxpages * PAGE_SIZE)
+                       len = maxpages * PAGE_SIZE;
+               addr &= ~(PAGE_SIZE - 1);
+               n = DIV_ROUND_UP(len, PAGE_SIZE);
+               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
+               if (unlikely(res < 0))
+                       return res;
+               return (res == n ? len : res * PAGE_SIZE) - *start;
+       0;}),({
+               /* can't be more than PAGE_SIZE */
+               *start = v.bv_offset;
+               get_page(*pages = v.bv_page);
+               return v.bv_len;
+       }),({
+               return -EFAULT;
+       })
+       )
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_get_pages);
+
+static struct page **get_pages_array(size_t n)
+{
+       struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
+       if (!p)
+               p = vmalloc(n * sizeof(struct page *));
+       return p;
+}
+
+ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
+                  struct page ***pages, size_t maxsize,
+                  size_t *start)
+{
+       struct page **p;
+
+       if (maxsize > i->count)
+               maxsize = i->count;
+
+       if (!maxsize)
+               return 0;
+
+       iterate_all_kinds(i, maxsize, v, ({
+               unsigned long addr = (unsigned long)v.iov_base;
+               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
+               int n;
+               int res;
+
+               addr &= ~(PAGE_SIZE - 1);
+               n = DIV_ROUND_UP(len, PAGE_SIZE);
+               p = get_pages_array(n);
+               if (!p)
+                       return -ENOMEM;
+               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
+               if (unlikely(res < 0)) {
+                       kvfree(p);
+                       return res;
+               }
+               *pages = p;
+               return (res == n ? len : res * PAGE_SIZE) - *start;
+       0;}),({
+               /* can't be more than PAGE_SIZE */
+               *start = v.bv_offset;
+               *pages = p = get_pages_array(1);
+               if (!p)
+                       return -ENOMEM;
+               get_page(*p = v.bv_page);
+               return v.bv_len;
+       }),({
+               return -EFAULT;
+       })
+       )
+       return 0;
+}
+EXPORT_SYMBOL(iov_iter_get_pages_alloc);
+
+size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
+                              struct iov_iter *i)
+{
+       char *to = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       sum = *csum;
+       iterate_and_advance(i, bytes, v, ({
+               int err = 0;
+               next = csum_and_copy_from_user(v.iov_base, 
+                                              (to += v.iov_len) - v.iov_len,
+                                              v.iov_len, 0, &err);
+               if (!err) {
+                       sum = csum_block_add(sum, next, off);
+                       off += v.iov_len;
+               }
+               err ? v.iov_len : 0;
+       }), ({
+               char *p = kmap_atomic(v.bv_page);
+               next = csum_partial_copy_nocheck(p + v.bv_offset,
+                                                (to += v.bv_len) - v.bv_len,
+                                                v.bv_len, 0);
+               kunmap_atomic(p);
+               sum = csum_block_add(sum, next, off);
+               off += v.bv_len;
+       }),({
+               next = csum_partial_copy_nocheck(v.iov_base,
+                                                (to += v.iov_len) - v.iov_len,
+                                                v.iov_len, 0);
+               sum = csum_block_add(sum, next, off);
+               off += v.iov_len;
+       })
+       )
+       *csum = sum;
+       return bytes;
+}
+EXPORT_SYMBOL(csum_and_copy_from_iter);
+
+size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
+                            struct iov_iter *i)
+{
+       char *from = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       sum = *csum;
+       iterate_and_advance(i, bytes, v, ({
+               int err = 0;
+               next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
+                                            v.iov_base, 
+                                            v.iov_len, 0, &err);
+               if (!err) {
+                       sum = csum_block_add(sum, next, off);
+                       off += v.iov_len;
+               }
+               err ? v.iov_len : 0;
+       }), ({
+               char *p = kmap_atomic(v.bv_page);
+               next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len,
+                                                p + v.bv_offset,
+                                                v.bv_len, 0);
+               kunmap_atomic(p);
+               sum = csum_block_add(sum, next, off);
+               off += v.bv_len;
+       }),({
+               next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len,
+                                                v.iov_base,
+                                                v.iov_len, 0);
+               sum = csum_block_add(sum, next, off);
+               off += v.iov_len;
+       })
+       )
+       *csum = sum;
+       return bytes;
+}
+EXPORT_SYMBOL(csum_and_copy_to_iter);
+
+int iov_iter_npages(const struct iov_iter *i, int maxpages)
+{
+       size_t size = i->count;
+       int npages = 0;
+
+       if (!size)
+               return 0;
+
+       iterate_all_kinds(i, size, v, ({
+               unsigned long p = (unsigned long)v.iov_base;
+               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
+                       - p / PAGE_SIZE;
+               if (npages >= maxpages)
+                       return maxpages;
+       0;}),({
+               npages++;
+               if (npages >= maxpages)
+                       return maxpages;
+       }),({
+               unsigned long p = (unsigned long)v.iov_base;
+               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
+                       - p / PAGE_SIZE;
+               if (npages >= maxpages)
+                       return maxpages;
+       })
+       )
+       return npages;
+}
+EXPORT_SYMBOL(iov_iter_npages);
+
+const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
+{
+       *new = *old;
+       if (new->type & ITER_BVEC)
+               return new->bvec = kmemdup(new->bvec,
+                                   new->nr_segs * sizeof(struct bio_vec),
+                                   flags);
+       else
+               /* iovec and kvec have identical layout */
+               return new->iov = kmemdup(new->iov,
+                                  new->nr_segs * sizeof(struct iovec),
+                                  flags);
+}
+EXPORT_SYMBOL(dup_iter);
index e97dbd51e7569f6a7ba273227752f2cdbcaebb49..03d7fcb420b5d60c564ad10935011ed8a6556b69 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 7a85967060a518a43c5da9125a03d701ab892304..f0f5c5c3de12e1a23b5aeebc7ec05da6e78d3c14 100644 (file)
@@ -139,6 +139,9 @@ static int lz4_uncompress(const char *source, char *dest, int osize)
                        /* Error: request to write beyond destination buffer */
                        if (cpy > oend)
                                goto _output_error;
+                       if ((ref + COPYLENGTH) > oend ||
+                                       (op + COPYLENGTH) > oend)
+                               goto _output_error;
                        LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
                        while (op < cpy)
                                *op++ = *ref++;
index 76a1b59523ab05907403f4f9bd5dc547fca1bcab..f5907d23272d48562c69b911e5a0a619e3f4c180 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 9cc4c4a90d00686228bebdfe55b212c34e98206f..b5344ef4c6846c4f9256c1d0d418f774284c8fcc 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/log2.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
@@ -217,15 +218,15 @@ static void bucket_table_free(const struct bucket_table *tbl)
 static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
                                               size_t nbuckets)
 {
-       struct bucket_table *tbl;
+       struct bucket_table *tbl = NULL;
        size_t size;
        int i;
 
        size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]);
-       tbl = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+       if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
+               tbl = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
        if (tbl == NULL)
                tbl = vzalloc(size);
-
        if (tbl == NULL)
                return NULL;
 
@@ -247,26 +248,24 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
  * @ht:                hash table
  * @new_size:  new table size
  */
-bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size)
+static bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size)
 {
        /* Expand table when exceeding 75% load */
        return atomic_read(&ht->nelems) > (new_size / 4 * 3) &&
-              (ht->p.max_shift && atomic_read(&ht->shift) < ht->p.max_shift);
+              (!ht->p.max_shift || atomic_read(&ht->shift) < ht->p.max_shift);
 }
-EXPORT_SYMBOL_GPL(rht_grow_above_75);
 
 /**
  * rht_shrink_below_30 - returns true if nelems < 0.3 * table-size
  * @ht:                hash table
  * @new_size:  new table size
  */
-bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size)
+static bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size)
 {
        /* Shrink table beneath 30% load */
        return atomic_read(&ht->nelems) < (new_size * 3 / 10) &&
               (atomic_read(&ht->shift) > ht->p.min_shift);
 }
-EXPORT_SYMBOL_GPL(rht_shrink_below_30);
 
 static void lock_buckets(struct bucket_table *new_tbl,
                         struct bucket_table *old_tbl, unsigned int hash)
@@ -414,6 +413,7 @@ int rhashtable_expand(struct rhashtable *ht)
                        }
                }
                unlock_buckets(new_tbl, old_tbl, new_hash);
+               cond_resched();
        }
 
        /* Unzip interleaved hash chains */
@@ -437,6 +437,7 @@ int rhashtable_expand(struct rhashtable *ht)
                                complete = false;
 
                        unlock_buckets(new_tbl, old_tbl, old_hash);
+                       cond_resched();
                }
        }
 
@@ -495,6 +496,7 @@ int rhashtable_shrink(struct rhashtable *ht)
                                   tbl->buckets[new_hash + new_tbl->size]);
 
                unlock_buckets(new_tbl, tbl, new_hash);
+               cond_resched();
        }
 
        /* Publish the new, valid hash table */
@@ -528,31 +530,19 @@ static void rht_deferred_worker(struct work_struct *work)
        list_for_each_entry(walker, &ht->walkers, list)
                walker->resize = true;
 
-       if (ht->p.grow_decision && ht->p.grow_decision(ht, tbl->size))
+       if (rht_grow_above_75(ht, tbl->size))
                rhashtable_expand(ht);
-       else if (ht->p.shrink_decision && ht->p.shrink_decision(ht, tbl->size))
+       else if (rht_shrink_below_30(ht, tbl->size))
                rhashtable_shrink(ht);
-
 unlock:
        mutex_unlock(&ht->mutex);
 }
 
-static void rhashtable_wakeup_worker(struct rhashtable *ht)
-{
-       struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht);
-       struct bucket_table *new_tbl = rht_dereference_rcu(ht->future_tbl, ht);
-       size_t size = tbl->size;
-
-       /* Only adjust the table if no resizing is currently in progress. */
-       if (tbl == new_tbl &&
-           ((ht->p.grow_decision && ht->p.grow_decision(ht, size)) ||
-            (ht->p.shrink_decision && ht->p.shrink_decision(ht, size))))
-               schedule_work(&ht->run_work);
-}
-
 static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
-                               struct bucket_table *tbl, u32 hash)
+                               struct bucket_table *tbl,
+                               const struct bucket_table *old_tbl, u32 hash)
 {
+       bool no_resize_running = tbl == old_tbl;
        struct rhash_head *head;
 
        hash = rht_bucket_index(tbl, hash);
@@ -568,8 +558,8 @@ static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
        rcu_assign_pointer(tbl->buckets[hash], obj);
 
        atomic_inc(&ht->nelems);
-
-       rhashtable_wakeup_worker(ht);
+       if (no_resize_running && rht_grow_above_75(ht, tbl->size))
+               schedule_work(&ht->run_work);
 }
 
 /**
@@ -599,7 +589,7 @@ void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj)
        hash = obj_raw_hashfn(ht, rht_obj(ht, obj));
 
        lock_buckets(tbl, old_tbl, hash);
-       __rhashtable_insert(ht, obj, tbl, hash);
+       __rhashtable_insert(ht, obj, tbl, old_tbl, hash);
        unlock_buckets(tbl, old_tbl, hash);
 
        rcu_read_unlock();
@@ -681,8 +671,11 @@ found:
        unlock_buckets(new_tbl, old_tbl, new_hash);
 
        if (ret) {
+               bool no_resize_running = new_tbl == old_tbl;
+
                atomic_dec(&ht->nelems);
-               rhashtable_wakeup_worker(ht);
+               if (no_resize_running && rht_shrink_below_30(ht, new_tbl->size))
+                       schedule_work(&ht->run_work);
        }
 
        rcu_read_unlock();
@@ -852,7 +845,7 @@ bool rhashtable_lookup_compare_insert(struct rhashtable *ht,
                goto exit;
        }
 
-       __rhashtable_insert(ht, obj, new_tbl, new_hash);
+       __rhashtable_insert(ht, obj, new_tbl, old_tbl, new_hash);
 
 exit:
        unlock_buckets(new_tbl, old_tbl, new_hash);
@@ -894,6 +887,9 @@ int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter)
        if (!iter->walker)
                return -ENOMEM;
 
+       INIT_LIST_HEAD(&iter->walker->list);
+       iter->walker->resize = false;
+
        mutex_lock(&ht->mutex);
        list_add(&iter->walker->list, &ht->walkers);
        mutex_unlock(&ht->mutex);
@@ -1111,8 +1107,7 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params)
        if (!ht->p.hash_rnd)
                get_random_bytes(&ht->p.hash_rnd, sizeof(ht->p.hash_rnd));
 
-       if (ht->p.grow_decision || ht->p.shrink_decision)
-               INIT_WORK(&ht->run_work, rht_deferred_worker);
+       INIT_WORK(&ht->run_work, rht_deferred_worker);
 
        return 0;
 }
@@ -1130,8 +1125,7 @@ void rhashtable_destroy(struct rhashtable *ht)
 {
        ht->being_destroyed = true;
 
-       if (ht->p.grow_decision || ht->p.shrink_decision)
-               cancel_work_sync(&ht->run_work);
+       cancel_work_sync(&ht->run_work);
 
        mutex_lock(&ht->mutex);
        bucket_table_free(rht_dereference(ht->tbl, ht));
index 88c0854bd7527aca54ca5ec3f533efe896c5477a..5c94e1012a91f9ea65b20ca130f3f4aa4fb337f5 100644 (file)
@@ -61,7 +61,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
 
        if (s->len < s->size) {
                len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
-               if (seq_buf_can_fit(s, len)) {
+               if (s->len + len < s->size) {
                        s->len += len;
                        return 0;
                }
@@ -118,7 +118,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
 
        if (s->len < s->size) {
                ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
-               if (seq_buf_can_fit(s, ret)) {
+               if (s->len + ret < s->size) {
                        s->len += ret;
                        return 0;
                }
index 1dfeba73fc743718d94551e9356ec8c6580a1fac..67c7593d1dd69c91f646e21e47b589c40c808837 100644 (file)
@@ -191,18 +191,18 @@ error:
        return err;
 }
 
+static struct rhashtable ht;
+
 static int __init test_rht_init(void)
 {
-       struct rhashtable ht;
        struct rhashtable_params params = {
                .nelem_hint = TEST_HT_SIZE,
                .head_offset = offsetof(struct test_obj, node),
                .key_offset = offsetof(struct test_obj, value),
                .key_len = sizeof(int),
                .hashfn = jhash,
+               .max_shift = 1, /* we expand/shrink manually here */
                .nulls_base = (3U << RHT_BASE_SHIFT),
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
        int err;
 
@@ -222,6 +222,11 @@ static int __init test_rht_init(void)
        return err;
 }
 
+static void __exit test_rht_exit(void)
+{
+}
+
 module_init(test_rht_init);
+module_exit(test_rht_exit);
 
 MODULE_LICENSE("GPL v2");
index 3c1caa2693bd22bad68864896c5e02737aac31c5..15dbe9903c273f87c3e7c6a09e3c4a659647bd48 100644 (file)
@@ -21,7 +21,7 @@ obj-y                 := filemap.o mempool.o oom_kill.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
                           compaction.o vmacache.o \
                           interval_tree.o list_lru.o workingset.o \
-                          iov_iter.o debug.o $(mmu-y)
+                          debug.o $(mmu-y)
 
 obj-y += init-mm.o
 
index 75016fd1de906280490352006ffc6845c90ddc46..68ecb7a42983a589fe4c057f109e327b352c8a0b 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -64,15 +64,17 @@ static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
        return (1UL << (align_order - cma->order_per_bit)) - 1;
 }
 
+/*
+ * Find a PFN aligned to the specified order and return an offset represented in
+ * order_per_bits.
+ */
 static unsigned long cma_bitmap_aligned_offset(struct cma *cma, int align_order)
 {
-       unsigned int alignment;
-
        if (align_order <= cma->order_per_bit)
                return 0;
-       alignment = 1UL << (align_order - cma->order_per_bit);
-       return ALIGN(cma->base_pfn, alignment) -
-               (cma->base_pfn >> cma->order_per_bit);
+
+       return (ALIGN(cma->base_pfn, (1UL << align_order))
+               - cma->base_pfn) >> cma->order_per_bit;
 }
 
 static unsigned long cma_bitmap_maxno(struct cma *cma)
index fc00c8cb5a82ee89addf4d2ee8983894bf6aa5d1..6817b0350c71c43b0f89a4972ce19c51a2408a2b 100644 (file)
@@ -1260,6 +1260,7 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        int target_nid, last_cpupid = -1;
        bool page_locked;
        bool migrated = false;
+       bool was_writable;
        int flags = 0;
 
        /* A PROT_NONE fault should not end up here */
@@ -1291,12 +1292,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                flags |= TNF_FAULT_LOCAL;
        }
 
-       /*
-        * Avoid grouping on DSO/COW pages in specific and RO pages
-        * in general, RO pages shouldn't hurt as much anyway since
-        * they can be in shared cache state.
-        */
-       if (!pmd_write(pmd))
+       /* See similar comment in do_numa_page for explanation */
+       if (!(vma->vm_flags & VM_WRITE))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -1353,12 +1350,17 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (migrated) {
                flags |= TNF_MIGRATED;
                page_nid = target_nid;
-       }
+       } else
+               flags |= TNF_MIGRATE_FAIL;
 
        goto out;
 clear_pmdnuma:
        BUG_ON(!PageLocked(page));
+       was_writable = pmd_write(pmd);
        pmd = pmd_modify(pmd, vma->vm_page_prot);
+       pmd = pmd_mkyoung(pmd);
+       if (was_writable)
+               pmd = pmd_mkwrite(pmd);
        set_pmd_at(mm, haddr, pmdp, pmd);
        update_mmu_cache_pmd(vma, addr, pmdp);
        unlock_page(page);
@@ -1482,6 +1484,8 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
 
        if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
                pmd_t entry;
+               bool preserve_write = prot_numa && pmd_write(*pmd);
+               ret = 1;
 
                /*
                 * Avoid trapping faults against the zero page. The read-only
@@ -1490,16 +1494,17 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                 */
                if (prot_numa && is_huge_zero_pmd(*pmd)) {
                        spin_unlock(ptl);
-                       return 0;
+                       return ret;
                }
 
                if (!prot_numa || !pmd_protnone(*pmd)) {
-                       ret = 1;
                        entry = pmdp_get_and_clear_notify(mm, addr, pmd);
                        entry = pmd_modify(entry, newprot);
+                       if (preserve_write)
+                               entry = pmd_mkwrite(entry);
                        ret = HPAGE_PMD_NR;
                        set_pmd_at(mm, addr, pmd, entry);
-                       BUG_ON(pmd_write(entry));
+                       BUG_ON(!preserve_write && pmd_write(entry));
                }
                spin_unlock(ptl);
        }
index 0a9ac6c268325a6ca9096bfc784cfbf68ac6a65e..c41b2a0ee2736e4f7df74c440ceb90bd5fcceecb 100644 (file)
@@ -917,7 +917,6 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
        __SetPageHead(page);
        __ClearPageReserved(page);
        for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
-               __SetPageTail(p);
                /*
                 * For gigantic hugepages allocated through bootmem at
                 * boot, it's safer to be consistent with the not-gigantic
@@ -933,6 +932,9 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
                __ClearPageReserved(p);
                set_page_count(p, 0);
                p->first_page = page;
+               /* Make sure p->first_page is always valid for PageTail() */
+               smp_wmb();
+               __SetPageTail(p);
        }
 }
 
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
deleted file mode 100644 (file)
index 8277320..0000000
+++ /dev/null
@@ -1,753 +0,0 @@
-#include <linux/export.h>
-#include <linux/uio.h>
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <net/checksum.h>
-
-#define iterate_iovec(i, n, __v, __p, skip, STEP) {    \
-       size_t left;                                    \
-       size_t wanted = n;                              \
-       __p = i->iov;                                   \
-       __v.iov_len = min(n, __p->iov_len - skip);      \
-       if (likely(__v.iov_len)) {                      \
-               __v.iov_base = __p->iov_base + skip;    \
-               left = (STEP);                          \
-               __v.iov_len -= left;                    \
-               skip += __v.iov_len;                    \
-               n -= __v.iov_len;                       \
-       } else {                                        \
-               left = 0;                               \
-       }                                               \
-       while (unlikely(!left && n)) {                  \
-               __p++;                                  \
-               __v.iov_len = min(n, __p->iov_len);     \
-               if (unlikely(!__v.iov_len))             \
-                       continue;                       \
-               __v.iov_base = __p->iov_base;           \
-               left = (STEP);                          \
-               __v.iov_len -= left;                    \
-               skip = __v.iov_len;                     \
-               n -= __v.iov_len;                       \
-       }                                               \
-       n = wanted - n;                                 \
-}
-
-#define iterate_kvec(i, n, __v, __p, skip, STEP) {     \
-       size_t wanted = n;                              \
-       __p = i->kvec;                                  \
-       __v.iov_len = min(n, __p->iov_len - skip);      \
-       if (likely(__v.iov_len)) {                      \
-               __v.iov_base = __p->iov_base + skip;    \
-               (void)(STEP);                           \
-               skip += __v.iov_len;                    \
-               n -= __v.iov_len;                       \
-       }                                               \
-       while (unlikely(n)) {                           \
-               __p++;                                  \
-               __v.iov_len = min(n, __p->iov_len);     \
-               if (unlikely(!__v.iov_len))             \
-                       continue;                       \
-               __v.iov_base = __p->iov_base;           \
-               (void)(STEP);                           \
-               skip = __v.iov_len;                     \
-               n -= __v.iov_len;                       \
-       }                                               \
-       n = wanted;                                     \
-}
-
-#define iterate_bvec(i, n, __v, __p, skip, STEP) {     \
-       size_t wanted = n;                              \
-       __p = i->bvec;                                  \
-       __v.bv_len = min_t(size_t, n, __p->bv_len - skip);      \
-       if (likely(__v.bv_len)) {                       \
-               __v.bv_page = __p->bv_page;             \
-               __v.bv_offset = __p->bv_offset + skip;  \
-               (void)(STEP);                           \
-               skip += __v.bv_len;                     \
-               n -= __v.bv_len;                        \
-       }                                               \
-       while (unlikely(n)) {                           \
-               __p++;                                  \
-               __v.bv_len = min_t(size_t, n, __p->bv_len);     \
-               if (unlikely(!__v.bv_len))              \
-                       continue;                       \
-               __v.bv_page = __p->bv_page;             \
-               __v.bv_offset = __p->bv_offset;         \
-               (void)(STEP);                           \
-               skip = __v.bv_len;                      \
-               n -= __v.bv_len;                        \
-       }                                               \
-       n = wanted;                                     \
-}
-
-#define iterate_all_kinds(i, n, v, I, B, K) {                  \
-       size_t skip = i->iov_offset;                            \
-       if (unlikely(i->type & ITER_BVEC)) {                    \
-               const struct bio_vec *bvec;                     \
-               struct bio_vec v;                               \
-               iterate_bvec(i, n, v, bvec, skip, (B))          \
-       } else if (unlikely(i->type & ITER_KVEC)) {             \
-               const struct kvec *kvec;                        \
-               struct kvec v;                                  \
-               iterate_kvec(i, n, v, kvec, skip, (K))          \
-       } else {                                                \
-               const struct iovec *iov;                        \
-               struct iovec v;                                 \
-               iterate_iovec(i, n, v, iov, skip, (I))          \
-       }                                                       \
-}
-
-#define iterate_and_advance(i, n, v, I, B, K) {                        \
-       size_t skip = i->iov_offset;                            \
-       if (unlikely(i->type & ITER_BVEC)) {                    \
-               const struct bio_vec *bvec;                     \
-               struct bio_vec v;                               \
-               iterate_bvec(i, n, v, bvec, skip, (B))          \
-               if (skip == bvec->bv_len) {                     \
-                       bvec++;                                 \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= bvec - i->bvec;                   \
-               i->bvec = bvec;                                 \
-       } else if (unlikely(i->type & ITER_KVEC)) {             \
-               const struct kvec *kvec;                        \
-               struct kvec v;                                  \
-               iterate_kvec(i, n, v, kvec, skip, (K))          \
-               if (skip == kvec->iov_len) {                    \
-                       kvec++;                                 \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= kvec - i->kvec;                   \
-               i->kvec = kvec;                                 \
-       } else {                                                \
-               const struct iovec *iov;                        \
-               struct iovec v;                                 \
-               iterate_iovec(i, n, v, iov, skip, (I))          \
-               if (skip == iov->iov_len) {                     \
-                       iov++;                                  \
-                       skip = 0;                               \
-               }                                               \
-               i->nr_segs -= iov - i->iov;                     \
-               i->iov = iov;                                   \
-       }                                                       \
-       i->count -= n;                                          \
-       i->iov_offset = skip;                                   \
-}
-
-static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-       void *kaddr, *from;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       if (!fault_in_pages_writeable(buf, copy)) {
-               kaddr = kmap_atomic(page);
-               from = kaddr + offset;
-
-               /* first chunk, usually the only one */
-               left = __copy_to_user_inatomic(buf, from, copy);
-               copy -= left;
-               skip += copy;
-               from += copy;
-               bytes -= copy;
-
-               while (unlikely(!left && bytes)) {
-                       iov++;
-                       buf = iov->iov_base;
-                       copy = min(bytes, iov->iov_len);
-                       left = __copy_to_user_inatomic(buf, from, copy);
-                       copy -= left;
-                       skip = copy;
-                       from += copy;
-                       bytes -= copy;
-               }
-               if (likely(!bytes)) {
-                       kunmap_atomic(kaddr);
-                       goto done;
-               }
-               offset = from - kaddr;
-               buf += copy;
-               kunmap_atomic(kaddr);
-               copy = min(bytes, iov->iov_len - skip);
-       }
-       /* Too bad - revert to non-atomic kmap */
-       kaddr = kmap(page);
-       from = kaddr + offset;
-       left = __copy_to_user(buf, from, copy);
-       copy -= left;
-       skip += copy;
-       from += copy;
-       bytes -= copy;
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __copy_to_user(buf, from, copy);
-               copy -= left;
-               skip = copy;
-               from += copy;
-               bytes -= copy;
-       }
-       kunmap(page);
-done:
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
-
-static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-       void *kaddr, *to;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       if (!fault_in_pages_readable(buf, copy)) {
-               kaddr = kmap_atomic(page);
-               to = kaddr + offset;
-
-               /* first chunk, usually the only one */
-               left = __copy_from_user_inatomic(to, buf, copy);
-               copy -= left;
-               skip += copy;
-               to += copy;
-               bytes -= copy;
-
-               while (unlikely(!left && bytes)) {
-                       iov++;
-                       buf = iov->iov_base;
-                       copy = min(bytes, iov->iov_len);
-                       left = __copy_from_user_inatomic(to, buf, copy);
-                       copy -= left;
-                       skip = copy;
-                       to += copy;
-                       bytes -= copy;
-               }
-               if (likely(!bytes)) {
-                       kunmap_atomic(kaddr);
-                       goto done;
-               }
-               offset = to - kaddr;
-               buf += copy;
-               kunmap_atomic(kaddr);
-               copy = min(bytes, iov->iov_len - skip);
-       }
-       /* Too bad - revert to non-atomic kmap */
-       kaddr = kmap(page);
-       to = kaddr + offset;
-       left = __copy_from_user(to, buf, copy);
-       copy -= left;
-       skip += copy;
-       to += copy;
-       bytes -= copy;
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __copy_from_user(to, buf, copy);
-               copy -= left;
-               skip = copy;
-               to += copy;
-               bytes -= copy;
-       }
-       kunmap(page);
-done:
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
-
-/*
- * Fault in the first iovec of the given iov_iter, to a maximum length
- * of bytes. Returns 0 on success, or non-zero if the memory could not be
- * accessed (ie. because it is an invalid address).
- *
- * writev-intensive code may want this to prefault several iovecs -- that
- * would be possible (callers must not rely on the fact that _only_ the
- * first iovec will be faulted with the current implementation).
- */
-int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
-{
-       if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
-               char __user *buf = i->iov->iov_base + i->iov_offset;
-               bytes = min(bytes, i->iov->iov_len - i->iov_offset);
-               return fault_in_pages_readable(buf, bytes);
-       }
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_fault_in_readable);
-
-void iov_iter_init(struct iov_iter *i, int direction,
-                       const struct iovec *iov, unsigned long nr_segs,
-                       size_t count)
-{
-       /* It will get better.  Eventually... */
-       if (segment_eq(get_fs(), KERNEL_DS)) {
-               direction |= ITER_KVEC;
-               i->type = direction;
-               i->kvec = (struct kvec *)iov;
-       } else {
-               i->type = direction;
-               i->iov = iov;
-       }
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_init);
-
-static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
-{
-       char *from = kmap_atomic(page);
-       memcpy(to, from + offset, len);
-       kunmap_atomic(from);
-}
-
-static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len)
-{
-       char *to = kmap_atomic(page);
-       memcpy(to + offset, from, len);
-       kunmap_atomic(to);
-}
-
-static void memzero_page(struct page *page, size_t offset, size_t len)
-{
-       char *addr = kmap_atomic(page);
-       memset(addr + offset, 0, len);
-       kunmap_atomic(addr);
-}
-
-size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *from = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len,
-                              v.iov_len),
-               memcpy_to_page(v.bv_page, v.bv_offset,
-                              (from += v.bv_len) - v.bv_len, v.bv_len),
-               memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_to_iter);
-
-size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *to = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base,
-                                v.iov_len),
-               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_from_iter);
-
-size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
-{
-       char *to = addr;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __copy_from_user_nocache((to += v.iov_len) - v.iov_len,
-                                        v.iov_base, v.iov_len),
-               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(copy_from_iter_nocache);
-
-size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       if (i->type & (ITER_BVEC|ITER_KVEC)) {
-               void *kaddr = kmap_atomic(page);
-               size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
-               kunmap_atomic(kaddr);
-               return wanted;
-       } else
-               return copy_page_to_iter_iovec(page, offset, bytes, i);
-}
-EXPORT_SYMBOL(copy_page_to_iter);
-
-size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
-{
-       if (i->type & (ITER_BVEC|ITER_KVEC)) {
-               void *kaddr = kmap_atomic(page);
-               size_t wanted = copy_from_iter(kaddr + offset, bytes, i);
-               kunmap_atomic(kaddr);
-               return wanted;
-       } else
-               return copy_page_from_iter_iovec(page, offset, bytes, i);
-}
-EXPORT_SYMBOL(copy_page_from_iter);
-
-size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
-{
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       iterate_and_advance(i, bytes, v,
-               __clear_user(v.iov_base, v.iov_len),
-               memzero_page(v.bv_page, v.bv_offset, v.bv_len),
-               memset(v.iov_base, 0, v.iov_len)
-       )
-
-       return bytes;
-}
-EXPORT_SYMBOL(iov_iter_zero);
-
-size_t iov_iter_copy_from_user_atomic(struct page *page,
-               struct iov_iter *i, unsigned long offset, size_t bytes)
-{
-       char *kaddr = kmap_atomic(page), *p = kaddr + offset;
-       iterate_all_kinds(i, bytes, v,
-               __copy_from_user_inatomic((p += v.iov_len) - v.iov_len,
-                                         v.iov_base, v.iov_len),
-               memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page,
-                                v.bv_offset, v.bv_len),
-               memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
-       )
-       kunmap_atomic(kaddr);
-       return bytes;
-}
-EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
-
-void iov_iter_advance(struct iov_iter *i, size_t size)
-{
-       iterate_and_advance(i, size, v, 0, 0, 0)
-}
-EXPORT_SYMBOL(iov_iter_advance);
-
-/*
- * Return the count of just the current iov_iter segment.
- */
-size_t iov_iter_single_seg_count(const struct iov_iter *i)
-{
-       if (i->nr_segs == 1)
-               return i->count;
-       else if (i->type & ITER_BVEC)
-               return min(i->count, i->bvec->bv_len - i->iov_offset);
-       else
-               return min(i->count, i->iov->iov_len - i->iov_offset);
-}
-EXPORT_SYMBOL(iov_iter_single_seg_count);
-
-void iov_iter_kvec(struct iov_iter *i, int direction,
-                       const struct kvec *kvec, unsigned long nr_segs,
-                       size_t count)
-{
-       BUG_ON(!(direction & ITER_KVEC));
-       i->type = direction;
-       i->kvec = kvec;
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_kvec);
-
-void iov_iter_bvec(struct iov_iter *i, int direction,
-                       const struct bio_vec *bvec, unsigned long nr_segs,
-                       size_t count)
-{
-       BUG_ON(!(direction & ITER_BVEC));
-       i->type = direction;
-       i->bvec = bvec;
-       i->nr_segs = nr_segs;
-       i->iov_offset = 0;
-       i->count = count;
-}
-EXPORT_SYMBOL(iov_iter_bvec);
-
-unsigned long iov_iter_alignment(const struct iov_iter *i)
-{
-       unsigned long res = 0;
-       size_t size = i->count;
-
-       if (!size)
-               return 0;
-
-       iterate_all_kinds(i, size, v,
-               (res |= (unsigned long)v.iov_base | v.iov_len, 0),
-               res |= v.bv_offset | v.bv_len,
-               res |= (unsigned long)v.iov_base | v.iov_len
-       )
-       return res;
-}
-EXPORT_SYMBOL(iov_iter_alignment);
-
-ssize_t iov_iter_get_pages(struct iov_iter *i,
-                  struct page **pages, size_t maxsize, unsigned maxpages,
-                  size_t *start)
-{
-       if (maxsize > i->count)
-               maxsize = i->count;
-
-       if (!maxsize)
-               return 0;
-
-       iterate_all_kinds(i, maxsize, v, ({
-               unsigned long addr = (unsigned long)v.iov_base;
-               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
-               int n;
-               int res;
-
-               if (len > maxpages * PAGE_SIZE)
-                       len = maxpages * PAGE_SIZE;
-               addr &= ~(PAGE_SIZE - 1);
-               n = DIV_ROUND_UP(len, PAGE_SIZE);
-               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
-               if (unlikely(res < 0))
-                       return res;
-               return (res == n ? len : res * PAGE_SIZE) - *start;
-       0;}),({
-               /* can't be more than PAGE_SIZE */
-               *start = v.bv_offset;
-               get_page(*pages = v.bv_page);
-               return v.bv_len;
-       }),({
-               return -EFAULT;
-       })
-       )
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_get_pages);
-
-static struct page **get_pages_array(size_t n)
-{
-       struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
-       if (!p)
-               p = vmalloc(n * sizeof(struct page *));
-       return p;
-}
-
-ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
-                  struct page ***pages, size_t maxsize,
-                  size_t *start)
-{
-       struct page **p;
-
-       if (maxsize > i->count)
-               maxsize = i->count;
-
-       if (!maxsize)
-               return 0;
-
-       iterate_all_kinds(i, maxsize, v, ({
-               unsigned long addr = (unsigned long)v.iov_base;
-               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
-               int n;
-               int res;
-
-               addr &= ~(PAGE_SIZE - 1);
-               n = DIV_ROUND_UP(len, PAGE_SIZE);
-               p = get_pages_array(n);
-               if (!p)
-                       return -ENOMEM;
-               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
-               if (unlikely(res < 0)) {
-                       kvfree(p);
-                       return res;
-               }
-               *pages = p;
-               return (res == n ? len : res * PAGE_SIZE) - *start;
-       0;}),({
-               /* can't be more than PAGE_SIZE */
-               *start = v.bv_offset;
-               *pages = p = get_pages_array(1);
-               if (!p)
-                       return -ENOMEM;
-               get_page(*p = v.bv_page);
-               return v.bv_len;
-       }),({
-               return -EFAULT;
-       })
-       )
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_get_pages_alloc);
-
-size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
-                              struct iov_iter *i)
-{
-       char *to = addr;
-       __wsum sum, next;
-       size_t off = 0;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       sum = *csum;
-       iterate_and_advance(i, bytes, v, ({
-               int err = 0;
-               next = csum_and_copy_from_user(v.iov_base, 
-                                              (to += v.iov_len) - v.iov_len,
-                                              v.iov_len, 0, &err);
-               if (!err) {
-                       sum = csum_block_add(sum, next, off);
-                       off += v.iov_len;
-               }
-               err ? v.iov_len : 0;
-       }), ({
-               char *p = kmap_atomic(v.bv_page);
-               next = csum_partial_copy_nocheck(p + v.bv_offset,
-                                                (to += v.bv_len) - v.bv_len,
-                                                v.bv_len, 0);
-               kunmap_atomic(p);
-               sum = csum_block_add(sum, next, off);
-               off += v.bv_len;
-       }),({
-               next = csum_partial_copy_nocheck(v.iov_base,
-                                                (to += v.iov_len) - v.iov_len,
-                                                v.iov_len, 0);
-               sum = csum_block_add(sum, next, off);
-               off += v.iov_len;
-       })
-       )
-       *csum = sum;
-       return bytes;
-}
-EXPORT_SYMBOL(csum_and_copy_from_iter);
-
-size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
-                            struct iov_iter *i)
-{
-       char *from = addr;
-       __wsum sum, next;
-       size_t off = 0;
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       sum = *csum;
-       iterate_and_advance(i, bytes, v, ({
-               int err = 0;
-               next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
-                                            v.iov_base, 
-                                            v.iov_len, 0, &err);
-               if (!err) {
-                       sum = csum_block_add(sum, next, off);
-                       off += v.iov_len;
-               }
-               err ? v.iov_len : 0;
-       }), ({
-               char *p = kmap_atomic(v.bv_page);
-               next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len,
-                                                p + v.bv_offset,
-                                                v.bv_len, 0);
-               kunmap_atomic(p);
-               sum = csum_block_add(sum, next, off);
-               off += v.bv_len;
-       }),({
-               next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len,
-                                                v.iov_base,
-                                                v.iov_len, 0);
-               sum = csum_block_add(sum, next, off);
-               off += v.iov_len;
-       })
-       )
-       *csum = sum;
-       return bytes;
-}
-EXPORT_SYMBOL(csum_and_copy_to_iter);
-
-int iov_iter_npages(const struct iov_iter *i, int maxpages)
-{
-       size_t size = i->count;
-       int npages = 0;
-
-       if (!size)
-               return 0;
-
-       iterate_all_kinds(i, size, v, ({
-               unsigned long p = (unsigned long)v.iov_base;
-               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
-                       - p / PAGE_SIZE;
-               if (npages >= maxpages)
-                       return maxpages;
-       0;}),({
-               npages++;
-               if (npages >= maxpages)
-                       return maxpages;
-       }),({
-               unsigned long p = (unsigned long)v.iov_base;
-               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
-                       - p / PAGE_SIZE;
-               if (npages >= maxpages)
-                       return maxpages;
-       })
-       )
-       return npages;
-}
-EXPORT_SYMBOL(iov_iter_npages);
index 78fee632a7ee9b73d9d0d5498d76aeb58460e711..936d81661c478a89fd797e8b311b4c52291f2414 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/stacktrace.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/vmalloc.h>
 #include <linux/kasan.h>
 
 #include "kasan.h"
@@ -414,12 +415,19 @@ int kasan_module_alloc(void *addr, size_t size)
                        GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
                        PAGE_KERNEL, VM_NO_GUARD, NUMA_NO_NODE,
                        __builtin_return_address(0));
-       return ret ? 0 : -ENOMEM;
+
+       if (ret) {
+               find_vm_area(addr)->flags |= VM_KASAN;
+               return 0;
+       }
+
+       return -ENOMEM;
 }
 
-void kasan_module_free(void *addr)
+void kasan_free_shadow(const struct vm_struct *vm)
 {
-       vfree(kasan_mem_to_shadow(addr));
+       if (vm->flags & VM_KASAN)
+               vfree(kasan_mem_to_shadow(vm->addr));
 }
 
 static void register_global(struct kasan_global *global)
index d18d3a6e7337d944a36e1375b1f50fdce483961f..b34ef4a32a3b266768248743849e241183e112ed 100644 (file)
@@ -5232,7 +5232,9 @@ static void mem_cgroup_bind(struct cgroup_subsys_state *root_css)
         * on for the root memcg is enough.
         */
        if (cgroup_on_dfl(root_css->cgroup))
-               mem_cgroup_from_css(root_css)->use_hierarchy = true;
+               root_mem_cgroup->use_hierarchy = true;
+       else
+               root_mem_cgroup->use_hierarchy = false;
 }
 
 static u64 memory_current_read(struct cgroup_subsys_state *css,
@@ -5247,7 +5249,7 @@ static int memory_low_show(struct seq_file *m, void *v)
        unsigned long low = ACCESS_ONCE(memcg->low);
 
        if (low == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)low * PAGE_SIZE);
 
@@ -5262,7 +5264,7 @@ static ssize_t memory_low_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &low);
+       err = page_counter_memparse(buf, "max", &low);
        if (err)
                return err;
 
@@ -5277,7 +5279,7 @@ static int memory_high_show(struct seq_file *m, void *v)
        unsigned long high = ACCESS_ONCE(memcg->high);
 
        if (high == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)high * PAGE_SIZE);
 
@@ -5292,7 +5294,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &high);
+       err = page_counter_memparse(buf, "max", &high);
        if (err)
                return err;
 
@@ -5307,7 +5309,7 @@ static int memory_max_show(struct seq_file *m, void *v)
        unsigned long max = ACCESS_ONCE(memcg->memory.limit);
 
        if (max == PAGE_COUNTER_MAX)
-               seq_puts(m, "infinity\n");
+               seq_puts(m, "max\n");
        else
                seq_printf(m, "%llu\n", (u64)max * PAGE_SIZE);
 
@@ -5322,7 +5324,7 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
        int err;
 
        buf = strstrip(buf);
-       err = page_counter_memparse(buf, "infinity", &max);
+       err = page_counter_memparse(buf, "max", &max);
        if (err)
                return err;
 
@@ -5426,7 +5428,7 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
        if (memcg == root_mem_cgroup)
                return false;
 
-       if (page_counter_read(&memcg->memory) > memcg->low)
+       if (page_counter_read(&memcg->memory) >= memcg->low)
                return false;
 
        while (memcg != root) {
@@ -5435,7 +5437,7 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
                if (memcg == root_mem_cgroup)
                        break;
 
-               if (page_counter_read(&memcg->memory) > memcg->low)
+               if (page_counter_read(&memcg->memory) >= memcg->low)
                        return false;
        }
        return true;
index 8068893697bbdbb5d64f9d43508658d601a6932e..97839f5c8c303df324a1cec1dfacadb1b0bfa04c 100644 (file)
@@ -3035,6 +3035,7 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        int last_cpupid;
        int target_nid;
        bool migrated = false;
+       bool was_writable = pte_write(pte);
        int flags = 0;
 
        /* A PROT_NONE fault should not end up here */
@@ -3059,6 +3060,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        /* Make it present again */
        pte = pte_modify(pte, vma->vm_page_prot);
        pte = pte_mkyoung(pte);
+       if (was_writable)
+               pte = pte_mkwrite(pte);
        set_pte_at(mm, addr, ptep, pte);
        update_mmu_cache(vma, addr, ptep);
 
@@ -3069,11 +3072,14 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        }
 
        /*
-        * Avoid grouping on DSO/COW pages in specific and RO pages
-        * in general, RO pages shouldn't hurt as much anyway since
-        * they can be in shared cache state.
+        * Avoid grouping on RO pages in general. RO pages shouldn't hurt as
+        * much anyway since they can be in shared cache state. This misses
+        * the case where a mapping is writable but the process never writes
+        * to it but pte_write gets cleared during protection updates and
+        * pte_dirty has unpredictable behaviour between PTE scan updates,
+        * background writeback, dirty balancing and application behaviour.
         */
-       if (!pte_write(pte))
+       if (!(vma->vm_flags & VM_WRITE))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -3097,7 +3103,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (migrated) {
                page_nid = target_nid;
                flags |= TNF_MIGRATED;
-       }
+       } else
+               flags |= TNF_MIGRATE_FAIL;
 
 out:
        if (page_nid != -1)
index 9fab10795beabd723c29722a442ace37c349c66b..65842d688b7c9bb5dbfd2440fc07339fa94650f4 100644 (file)
@@ -1092,6 +1092,10 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
                        return NULL;
 
                arch_refresh_nodedata(nid, pgdat);
+       } else {
+               /* Reset the nr_zones and classzone_idx to 0 before reuse */
+               pgdat->nr_zones = 0;
+               pgdat->classzone_idx = 0;
        }
 
        /* we can use NODE_DATA(nid) from here */
@@ -1977,15 +1981,6 @@ void try_offline_node(int nid)
                if (is_vmalloc_addr(zone->wait_table))
                        vfree(zone->wait_table);
        }
-
-       /*
-        * Since there is no way to guarentee the address of pgdat/zone is not
-        * on stack of any kernel threads or used by other kernel objects
-        * without reference counting or other symchronizing method, do not
-        * reset node_data and free pgdat here. Just reset it to 0 and reuse
-        * the memory when the node is online again.
-        */
-       memset(pgdat, 0, sizeof(*pgdat));
 }
 EXPORT_SYMBOL(try_offline_node);
 
index 73cf0987088c36647fbb805278978bb656ff1fda..8a54cd214925872a66d4d1cc36b69ec6c6047324 100644 (file)
 
 int can_do_mlock(void)
 {
-       if (capable(CAP_IPC_LOCK))
-               return 1;
        if (rlimit(RLIMIT_MEMLOCK) != 0)
                return 1;
+       if (capable(CAP_IPC_LOCK))
+               return 1;
        return 0;
 }
 EXPORT_SYMBOL(can_do_mlock);
index da9990acc08b2d8014e342771a52650b47ee05fc..9ec50a368634a8d9a0824504d479b03798bdc402 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -774,10 +774,8 @@ again:                     remove_next = 1 + (end > next->vm_end);
 
                        importer->anon_vma = exporter->anon_vma;
                        error = anon_vma_clone(importer, exporter);
-                       if (error) {
-                               importer->anon_vma = NULL;
+                       if (error)
                                return error;
-                       }
                }
        }
 
index 44727811bf4cf62e3579261ee9699a37fab78b3d..88584838e7046bec724d68c0cafcd94eec65a040 100644 (file)
@@ -75,6 +75,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                oldpte = *pte;
                if (pte_present(oldpte)) {
                        pte_t ptent;
+                       bool preserve_write = prot_numa && pte_write(oldpte);
 
                        /*
                         * Avoid trapping faults against the zero or KSM
@@ -94,6 +95,8 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 
                        ptent = ptep_modify_prot_start(mm, addr, pte);
                        ptent = pte_modify(ptent, newprot);
+                       if (preserve_write)
+                               ptent = pte_mkwrite(ptent);
 
                        /* Avoid taking write faults for known dirty pages */
                        if (dirty_accountable && pte_dirty(ptent) &&
index 7296360fc057e5bbf67b9904501fdbe98a97b1b2..3fba2dc97c44bece0d6fb5754afdafb1dba6353e 100644 (file)
@@ -62,6 +62,7 @@ void *high_memory;
 EXPORT_SYMBOL(high_memory);
 struct page *mem_map;
 unsigned long max_mapnr;
+EXPORT_SYMBOL(max_mapnr);
 unsigned long highest_memmap_pfn;
 struct percpu_counter vm_committed_as;
 int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
@@ -1213,11 +1214,9 @@ static int do_mmap_private(struct vm_area_struct *vma,
        if (sysctl_nr_trim_pages && total - point >= sysctl_nr_trim_pages) {
                total = point;
                kdebug("try to alloc exact %lu pages", total);
-               base = alloc_pages_exact(len, GFP_KERNEL);
-       } else {
-               base = (void *)__get_free_pages(GFP_KERNEL, order);
        }
 
+       base = alloc_pages_exact(total << PAGE_SHIFT, GFP_KERNEL);
        if (!base)
                goto enomem;
 
index 45e187b2d97183a90df9a5ee8558404f9f1bd826..644bcb665773f6e53f50fe6599429595b506f0c5 100644 (file)
@@ -857,8 +857,11 @@ static void bdi_update_write_bandwidth(struct backing_dev_info *bdi,
         *                   bw * elapsed + write_bandwidth * (period - elapsed)
         * write_bandwidth = ---------------------------------------------------
         *                                          period
+        *
+        * @written may have decreased due to account_page_redirty().
+        * Avoid underflowing @bw calculation.
         */
-       bw = written - bdi->written_stamp;
+       bw = written - min(written, bdi->written_stamp);
        bw *= HZ;
        if (unlikely(elapsed > period)) {
                do_div(bw, elapsed);
@@ -922,7 +925,7 @@ static void global_update_bandwidth(unsigned long thresh,
                                    unsigned long now)
 {
        static DEFINE_SPINLOCK(dirty_lock);
-       static unsigned long update_time;
+       static unsigned long update_time = INITIAL_JIFFIES;
 
        /*
         * check locklessly first to optimize away locking for the most time
index a47f0b229a1aca202b15195c88ab93d52e65064f..40e29429e7b0995bd5799bd6263b18d6ce8261cb 100644 (file)
@@ -2353,8 +2353,15 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
                if (ac->high_zoneidx < ZONE_NORMAL)
                        goto out;
                /* The OOM killer does not compensate for light reclaim */
-               if (!(gfp_mask & __GFP_FS))
+               if (!(gfp_mask & __GFP_FS)) {
+                       /*
+                        * XXX: Page reclaim didn't yield anything,
+                        * and the OOM killer can't be invoked, but
+                        * keep looping as per should_alloc_retry().
+                        */
+                       *did_some_progress = 1;
                        goto out;
+               }
                /*
                 * GFP_THISNODE contains __GFP_NORETRY and we never hit this.
                 * Sanity check for bare calls of __GFP_THISNODE, not real OOM.
@@ -2366,7 +2373,8 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
                        goto out;
        }
        /* Exhausted what can be done so it's blamo time */
-       if (out_of_memory(ac->zonelist, gfp_mask, order, ac->nodemask, false))
+       if (out_of_memory(ac->zonelist, gfp_mask, order, ac->nodemask, false)
+                       || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL))
                *did_some_progress = 1;
 out:
        oom_zonelist_unlock(ac->zonelist, gfp_mask);
index 72f5ac381ab3253b6016583e0618be6f3e91367c..755a42c76eb4747623da51acdeb780b322b5ac06 100644 (file)
@@ -103,6 +103,7 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype)
 
                        if (!is_migrate_isolate_page(buddy)) {
                                __isolate_free_page(page, order);
+                               kernel_map_pages(page, (1 << order), 1);
                                set_page_refcounted(page);
                                isolated_page = page;
                        }
index 75c1f2878519171139ae2d0b6f1e24809067ab4a..29f2f8b853ae51be4f9e35fbc1495ad69297ff82 100644 (file)
@@ -265,8 +265,15 @@ int walk_page_range(unsigned long start, unsigned long end,
                        vma = vma->vm_next;
 
                        err = walk_page_test(start, next, walk);
-                       if (err > 0)
+                       if (err > 0) {
+                               /*
+                                * positive return values are purely for
+                                * controlling the pagewalk, so should never
+                                * be passed to the callers.
+                                */
+                               err = 0;
                                continue;
+                       }
                        if (err < 0)
                                break;
                }
index 5e3e09081164b83814683513c174445e67669a4b..c161a14b6a8fb127150678f18582ad6f0a29f55d 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -287,6 +287,13 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
        return 0;
 
  enomem_failure:
+       /*
+        * dst->anon_vma is dropped here otherwise its degree can be incorrectly
+        * decremented in unlink_anon_vmas().
+        * We can safely do this because callers of anon_vma_clone() don't care
+        * about dst->anon_vma if anon_vma_clone() failed.
+        */
+       dst->anon_vma = NULL;
        unlink_anon_vmas(dst);
        return -ENOMEM;
 }
index 2f17cb5f00a43f87b7868a2a2192dd911f4501bd..cf2d0ca010bc52efd5ea86c7f6ba760a5c3ef286 100644 (file)
@@ -1455,6 +1455,9 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
 
 bool shmem_mapping(struct address_space *mapping)
 {
+       if (!mapping->host)
+               return false;
+
        return mapping->host->i_sb->s_op == &shmem_ops;
 }
 
index 6832c4eab104d15ff3d3bd907c92591540facf01..82c473780c9188ecf7bfc393703f47793a2fbfe9 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2449,7 +2449,8 @@ redo:
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
                c = raw_cpu_ptr(s->cpu_slab);
-       } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid));
+       } while (IS_ENABLED(CONFIG_PREEMPT) &&
+                unlikely(tid != READ_ONCE(c->tid)));
 
        /*
         * Irqless object alloc/free algorithm used here depends on sequence
@@ -2718,7 +2719,8 @@ redo:
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
                c = raw_cpu_ptr(s->cpu_slab);
-       } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid));
+       } while (IS_ENABLED(CONFIG_PREEMPT) &&
+                unlikely(tid != READ_ONCE(c->tid)));
 
        /* Same with comment on barrier() in slab_alloc_node() */
        barrier();
index 35b25e1340ca49cf0a95bbc80c69490ec68b5554..49abccf29a29f65c4748a6decec00c27fec23c6d 100644 (file)
@@ -1418,6 +1418,7 @@ struct vm_struct *remove_vm_area(const void *addr)
                spin_unlock(&vmap_area_lock);
 
                vmap_debug_free_range(va->va_start, va->va_end);
+               kasan_free_shadow(vm);
                free_unmap_vmap_area(va);
                vm->size -= PAGE_SIZE;
 
index d8e376a5f0f13d9eed735f62b81367b7bc685ebe..36a1a739ad68ff57eace5ba4bc4166faf12c485b 100644 (file)
@@ -658,14 +658,30 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args)
 static void p9_virtio_remove(struct virtio_device *vdev)
 {
        struct virtio_chan *chan = vdev->priv;
-
-       if (chan->inuse)
-               p9_virtio_close(chan->client);
-       vdev->config->del_vqs(vdev);
+       unsigned long warning_time;
 
        mutex_lock(&virtio_9p_lock);
+
+       /* Remove self from list so we don't get new users. */
        list_del(&chan->chan_list);
+       warning_time = jiffies;
+
+       /* Wait for existing users to close. */
+       while (chan->inuse) {
+               mutex_unlock(&virtio_9p_lock);
+               msleep(250);
+               if (time_after(jiffies, warning_time + 10 * HZ)) {
+                       dev_emerg(&vdev->dev,
+                                 "p9_virtio_remove: waiting for device in use.\n");
+                       warning_time = jiffies;
+               }
+               mutex_lock(&virtio_9p_lock);
+       }
+
        mutex_unlock(&virtio_9p_lock);
+
+       vdev->config->del_vqs(vdev);
+
        sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
        kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
        kfree(chan->tag);
index fb57ab6b24f9ef8feea780179ad2e8284a9e532f..02c24cf63c344a3b15bcf87369da7f847150fab3 100644 (file)
@@ -190,6 +190,8 @@ static int __init br_init(void)
 {
        int err;
 
+       BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));
+
        err = stp_proto_register(&br_stp_proto);
        if (err < 0) {
                pr_err("bridge: can't register sap for STP\n");
index b087d278c6793f48f413082ff60fd8abbea49ff3..1849d96b3c91d82e20f85ca2579546857343d0f2 100644 (file)
@@ -563,6 +563,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
         */
        del_nbp(p);
 
+       dev_set_mtu(br->dev, br_min_mtu(br));
+
        spin_lock_bh(&br->lock);
        changed_addr = br_stp_recalculate_bridge_id(br);
        spin_unlock_bh(&br->lock);
index 769b185fefbd5f6bb6d4e68c1bcb0caeafa23d25..a6e2da0bc7184501ed5eb2bcef0e5169be2cf276 100644 (file)
@@ -281,7 +281,7 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
        int copylen;
 
        ret = -EOPNOTSUPP;
-       if (m->msg_flags&MSG_OOB)
+       if (flags & MSG_OOB)
                goto read_error;
 
        skb = skb_recv_datagram(sk, flags, 0 , &ret);
index 8bc7caa28e64ddc32d30f0054ac9dee708ba8f3f..434ba8557826ddf160fafd08a04949d546201692 100644 (file)
@@ -84,7 +84,7 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
        u16 tmp;
        u16 len;
        u16 hdrchks;
-       u16 pktchks;
+       int pktchks;
        struct cffrml *this;
        this = container_obj(layr);
 
index 1be0b521ac490143e60e3b2d5b02d7fd68c24087..f6c3b2137eeaacdc5cf38d1eac03e018d8f2d37b 100644 (file)
@@ -255,9 +255,9 @@ inline u16 cfpkt_getlen(struct cfpkt *pkt)
        return skb->len;
 }
 
-inline u16 cfpkt_iterate(struct cfpkt *pkt,
-                        u16 (*iter_func)(u16, void *, u16),
-                        u16 data)
+int cfpkt_iterate(struct cfpkt *pkt,
+                 u16 (*iter_func)(u16, void *, u16),
+                 u16 data)
 {
        /*
         * Don't care about the performance hit of linearizing,
index 66e08040ced7557ba19e7535815804bbcffca12a..32d710eaf1fc991b2ef4638fe8ccc95b84352ace 100644 (file)
@@ -259,6 +259,9 @@ int can_send(struct sk_buff *skb, int loop)
                goto inval_skb;
        }
 
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
        skb_reset_transport_header(skb);
 
index 3236b4167a32109b91b1eb28ae8bdf522c8db3f5..f7bd286a82807148bed32622e5de2f975450c877 100644 (file)
@@ -49,6 +49,13 @@ ssize_t get_compat_msghdr(struct msghdr *kmsg,
            __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
            __get_user(kmsg->msg_flags, &umsg->msg_flags))
                return -EFAULT;
+
+       if (!uaddr)
+               kmsg->msg_namelen = 0;
+
+       if (kmsg->msg_namelen < 0)
+               return -EINVAL;
+
        if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
        kmsg->msg_control = compat_ptr(tmp3);
@@ -711,24 +718,18 @@ static unsigned char nas[21] = {
 
 COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
 COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
                       unsigned int, vlen, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                              flags | MSG_CMSG_COMPAT);
 }
 
 COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
 {
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
        return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
@@ -751,9 +752,6 @@ COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
        int datagrams;
        struct timespec ktspec;
 
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
-
        if (timeout == NULL)
                return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                      flags | MSG_CMSG_COMPAT, NULL);
index 8f9710c62e20d58bcdcec3d184ca6344fbe5a57c..45109b70664e8abb1b7957aabd619c4e0d711db4 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 91f74f3eb20475439214d9692f9b17c8124a9c3a..aa378ecef1860d0c1e255c001aef9528b8198d6f 100644 (file)
@@ -98,6 +98,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
        [NETIF_F_RXALL_BIT] =            "rx-all",
        [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
        [NETIF_F_BUSY_POLL_BIT] =        "busy-poll",
+       [NETIF_F_HW_SWITCH_OFFLOAD_BIT] = "hw-switch-offload",
 };
 
 static const char
index 44706e81b2e03df3e9d39c1cd76879a4ede48d1e..e4fdc9dfb2c73fb371280464484ebcae87218be6 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 0c08062d1796337f25b9dbc2cbce68d5e3194037..1e2f46a69d50196f71f1fb7ae97e7732c2a8a059 100644 (file)
@@ -32,6 +32,9 @@ gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)
        return 0;
 
 nla_put_failure:
+       kfree(d->xstats);
+       d->xstats = NULL;
+       d->xstats_len = 0;
        spin_unlock_bh(d->lock);
        return -1;
 }
@@ -305,7 +308,9 @@ int
 gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
 {
        if (d->compat_xstats) {
-               d->xstats = st;
+               d->xstats = kmemdup(st, len, GFP_ATOMIC);
+               if (!d->xstats)
+                       goto err_out;
                d->xstats_len = len;
        }
 
@@ -313,6 +318,11 @@ gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
                return gnet_stats_copy(d, TCA_STATS_APP, st, len);
 
        return 0;
+
+err_out:
+       d->xstats_len = 0;
+       spin_unlock_bh(d->lock);
+       return -1;
 }
 EXPORT_SYMBOL(gnet_stats_copy_app);
 
@@ -345,6 +355,9 @@ gnet_stats_finish_copy(struct gnet_dump *d)
                        return -1;
        }
 
+       kfree(d->xstats);
+       d->xstats = NULL;
+       d->xstats_len = 0;
        spin_unlock_bh(d->lock);
        return 0;
 }
index cb5290b8c428c5c348b25d842ab9cf3797b70eba..70d3450588b2c73cbb4a3027f7f92e0c285b90d7 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 b4899f5b7388e8f0c825a433a1f633d6b087a0f9..508155b283ddcc73a967a2bc8068e67cb8cada7d 100644 (file)
@@ -1134,6 +1134,9 @@ static ssize_t pktgen_if_write(struct file *file,
                        return len;
 
                i += len;
+               if ((value > 1) &&
+                   (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
+                       return -ENOTSUPP;
                pkt_dev->burst = value < 1 ? 1 : value;
                sprintf(pg_result, "OK: burst=%d", pkt_dev->burst);
                return count;
index ab293a3066b34bc4f6af71701f0c12b9ab6e5a34..7ebed55b5f7d1b2d1faacea1a49e7f9e947f43d1 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 88c613eab142962dc44f2075378fce0b94349e8e..8e4ac97c84775f15c786020ff87a2ef22a8dbac8 100644 (file)
@@ -3621,13 +3621,14 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
 {
        struct sk_buff_head *q = &sk->sk_error_queue;
        struct sk_buff *skb, *skb_next;
+       unsigned long flags;
        int err = 0;
 
-       spin_lock_bh(&q->lock);
+       spin_lock_irqsave(&q->lock, flags);
        skb = __skb_dequeue(q);
        if (skb && (skb_next = skb_peek(q)))
                err = SKB_EXT_ERR(skb_next)->ee.ee_errno;
-       spin_unlock_bh(&q->lock);
+       spin_unlock_irqrestore(&q->lock, flags);
 
        sk->sk_err = err;
        if (err)
@@ -3732,9 +3733,13 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
                     struct sock *sk, int tstype)
 {
        struct sk_buff *skb;
-       bool tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       bool tsonly;
+
+       if (!sk)
+               return;
 
-       if (!sk || !skb_may_tx_timestamp(sk, tsonly))
+       tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       if (!skb_may_tx_timestamp(sk, tsonly))
                return;
 
        if (tsonly)
@@ -4172,7 +4177,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
        skb->ignore_df = 0;
        skb_dst_drop(skb);
        skb->mark = 0;
-       skb->sender_cpu = 0;
+       skb_sender_cpu_clear(skb);
        skb_init_secmark(skb);
        secpath_reset(skb);
        nf_reset(skb);
index 93c8b20c91e496648f7f2e5c769c062ca2dd679d..71e3e5f1eaa04816b8bdd1d34b4fd575f19793b9 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 433424804284cad8921a2efb6427a615b740ecc5..8ce351ffceb122568ae05587a0b1dc3544d476d7 100644 (file)
@@ -25,6 +25,8 @@
 static int zero = 0;
 static int one = 1;
 static int ushort_max = USHRT_MAX;
+static int min_sndbuf = SOCK_MIN_SNDBUF;
+static int min_rcvbuf = SOCK_MIN_RCVBUF;
 
 static int net_msg_warn;       /* Unused, but still a sysctl */
 
@@ -237,7 +239,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_sndbuf,
        },
        {
                .procname       = "rmem_max",
@@ -245,7 +247,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_rcvbuf,
        },
        {
                .procname       = "wmem_default",
@@ -253,7 +255,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_sndbuf,
        },
        {
                .procname       = "rmem_default",
@@ -261,7 +263,7 @@ static struct ctl_table net_core_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
+               .extra1         = &min_rcvbuf,
        },
        {
                .procname       = "dev_weight",
index 1d7c1256e8458d35e4a9f9daa392aba37672e1bf..3b81092771f8b7beb74349a84819046f7c080df1 100644 (file)
@@ -1062,7 +1062,7 @@ source_ok:
        if (decnet_debug_level & 16)
                printk(KERN_DEBUG
                       "dn_route_output_slow: initial checks complete."
-                      " dst=%o4x src=%04x oif=%d try_hard=%d\n",
+                      " dst=%04x src=%04x oif=%d try_hard=%d\n",
                       le16_to_cpu(fld.daddr), le16_to_cpu(fld.saddr),
                       fld.flowidn_oif, try_hard);
 
index faf7cc3483fe0822c26be6b915061ee8fdd8be9a..9d66a0f72f906733878de68e7f2e6bd80932c1b9 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 2173402d87e0f56f255d0b378f06fc51aa2d3fed..4dea2e0681d16409016ae09616127b22bbab3a1e 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 a138d75751df2fb46219168c01fd1bf5cce24d43..44d27469ae55982d1895021b79ba76a85c1324a8 100644 (file)
@@ -359,8 +359,11 @@ static void hsr_dev_destroy(struct net_device *hsr_dev)
        struct hsr_port *port;
 
        hsr = netdev_priv(hsr_dev);
+
+       rtnl_lock();
        hsr_for_each_port(hsr, port)
                hsr_del_port(port);
+       rtnl_unlock();
 
        del_timer_sync(&hsr->prune_timer);
        del_timer_sync(&hsr->announce_timer);
index 779d28b65417a6e62b687d8f5ea36d6be285f417..cd37d0011b424824fd113ffd4da59f36c116996a 100644 (file)
@@ -36,6 +36,10 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
                        return NOTIFY_DONE;     /* Not an HSR device */
                hsr = netdev_priv(dev);
                port = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
+               if (port == NULL) {
+                       /* Resend of notification concerning removed device? */
+                       return NOTIFY_DONE;
+               }
        } else {
                hsr = port->hsr;
        }
index a348dcbcd683e6858248bf17ee73e7e24d08b4ea..7d37366cc695554ae243f940869b46d26f598b65 100644 (file)
@@ -181,8 +181,10 @@ void hsr_del_port(struct hsr_port *port)
        list_del_rcu(&port->port_list);
 
        if (port != master) {
-               netdev_update_features(master->dev);
-               dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
+               if (master != NULL) {
+                       netdev_update_features(master->dev);
+                       dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
+               }
                netdev_rx_handler_unregister(port->dev);
                dev_set_promiscuity(port->dev, -1);
        }
@@ -192,5 +194,7 @@ void hsr_del_port(struct hsr_port *port)
         */
 
        synchronize_rcu();
-       dev_put(port->dev);
+
+       if (port != master)
+               dev_put(port->dev);
 }
index 57be71dd6a9e0163dceefd564bf71036c12dc9ba..23b9b3e86f4cd78987790f3456470318e3b82ece 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 14d02ea905b6bea37240f88054f0cd42db73c4c2..3e44b9b0b78ece392a1f1b0763b5445cadfb2557 100644 (file)
@@ -268,6 +268,7 @@ static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
                release_sock(sk);
                if (reqsk_queue_empty(&icsk->icsk_accept_queue))
                        timeo = schedule_timeout(timeo);
+               sched_annotate_sleep();
                lock_sock(sk);
                err = 0;
                if (!reqsk_queue_empty(&icsk->icsk_accept_queue))
index 81751f12645f6224a7f076dea1da2fc0d638819a..592aff37366bb932c0aeb2bad944b5470374ec21 100644 (file)
@@ -71,6 +71,20 @@ static inline void inet_diag_unlock_handler(
        mutex_unlock(&inet_diag_table_mutex);
 }
 
+static size_t inet_sk_attr_size(void)
+{
+       return    nla_total_size(sizeof(struct tcp_info))
+               + nla_total_size(1) /* INET_DIAG_SHUTDOWN */
+               + nla_total_size(1) /* INET_DIAG_TOS */
+               + nla_total_size(1) /* INET_DIAG_TCLASS */
+               + nla_total_size(sizeof(struct inet_diag_meminfo))
+               + nla_total_size(sizeof(struct inet_diag_msg))
+               + nla_total_size(SK_MEMINFO_VARS * sizeof(u32))
+               + nla_total_size(TCP_CA_NAME_MAX)
+               + nla_total_size(sizeof(struct tcpvegas_info))
+               + 64;
+}
+
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                              struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              struct user_namespace *user_ns,                   
@@ -326,9 +340,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s
        if (err)
                goto out;
 
-       rep = nlmsg_new(sizeof(struct inet_diag_msg) +
-                       sizeof(struct inet_diag_meminfo) +
-                       sizeof(struct tcp_info) + 64, GFP_KERNEL);
+       rep = nlmsg_new(inet_sk_attr_size(), GFP_KERNEL);
        if (!rep) {
                err = -ENOMEM;
                goto out;
index 787b3c294ce672244ce08c5426c03bbd1f71c0f3..d9bc28ac5d1b97340e79aae1eefcbac3f463251a 100644 (file)
@@ -67,6 +67,7 @@ static int ip_forward_finish(struct sk_buff *skb)
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
 
+       skb_sender_cpu_clear(skb);
        return dst_output(skb);
 }
 
index e5b6d0ddcb5808f662ca0b1fd5863d63e6b54b83..145a50c4d56630a5fc97283d85c3fa29e10ab476 100644 (file)
@@ -659,27 +659,30 @@ EXPORT_SYMBOL(ip_defrag);
 struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user)
 {
        struct iphdr iph;
+       int netoff;
        u32 len;
 
        if (skb->protocol != htons(ETH_P_IP))
                return skb;
 
-       if (!skb_copy_bits(skb, 0, &iph, sizeof(iph)))
+       netoff = skb_network_offset(skb);
+
+       if (skb_copy_bits(skb, netoff, &iph, sizeof(iph)) < 0)
                return skb;
 
        if (iph.ihl < 5 || iph.version != 4)
                return skb;
 
        len = ntohs(iph.tot_len);
-       if (skb->len < len || len < (iph.ihl * 4))
+       if (skb->len < netoff + len || len < (iph.ihl * 4))
                return skb;
 
        if (ip_is_fragment(&iph)) {
                skb = skb_share_check(skb, GFP_ATOMIC);
                if (skb) {
-                       if (!pskb_may_pull(skb, iph.ihl*4))
+                       if (!pskb_may_pull(skb, netoff + iph.ihl * 4))
                                return skb;
-                       if (pskb_trim_rcsum(skb, len))
+                       if (pskb_trim_rcsum(skb, netoff + len))
                                return skb;
                        memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
                        if (ip_defrag(skb, user))
index d68199d9b2b01faf7a5272862b7cd8658f08c8ae..a7aea2048a0d7a624ceb79923d25e9750ec6fa9a 100644 (file)
@@ -888,7 +888,8 @@ static int __ip_append_data(struct sock *sk,
        cork->length += length;
        if (((length > mtu) || (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
-           (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) {
+           (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
+           (sk->sk_type == SOCK_DGRAM)) {
                err = ip_ufo_append_data(sk, queue, getfrag, from, length,
                                         hh_len, fragheaderlen, transhdrlen,
                                         maxfraglen, flags);
index 31d8c71986b40e28e5c84f5e62d474a639d3bf91..5cd99271d3a6a07c17a915fddde7a5a0c8a86618 100644 (file)
@@ -432,17 +432,32 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf
                kfree_skb(skb);
 }
 
-static bool ipv4_pktinfo_prepare_errqueue(const struct sock *sk,
-                                         const struct sk_buff *skb,
-                                         int ee_origin)
+/* IPv4 supports cmsg on all imcp errors and some timestamps
+ *
+ * Timestamp code paths do not initialize the fields expected by cmsg:
+ * the PKTINFO fields in skb->cb[]. Fill those in here.
+ */
+static bool ipv4_datagram_support_cmsg(const struct sock *sk,
+                                      struct sk_buff *skb,
+                                      int ee_origin)
 {
-       struct in_pktinfo *info = PKTINFO_SKB_CB(skb);
+       struct in_pktinfo *info;
+
+       if (ee_origin == SO_EE_ORIGIN_ICMP)
+               return true;
 
-       if ((ee_origin != SO_EE_ORIGIN_TIMESTAMPING) ||
-           (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) ||
+       if (ee_origin == SO_EE_ORIGIN_LOCAL)
+               return false;
+
+       /* Support IP_PKTINFO on tstamp packets if requested, to correlate
+        * timestamp with egress dev. Not possible for packets without dev
+        * or without payload (SOF_TIMESTAMPING_OPT_TSONLY).
+        */
+       if ((!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) ||
            (!skb->dev))
                return false;
 
+       info = PKTINFO_SKB_CB(skb);
        info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr;
        info->ipi_ifindex = skb->dev->ifindex;
        return true;
@@ -483,7 +498,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        serr = SKB_EXT_ERR(skb);
 
-       if (sin && skb->len) {
+       if (sin && serr->port) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
                                                   serr->addr_offset);
@@ -496,9 +511,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        sin = &errhdr.offender;
        memset(sin, 0, sizeof(*sin));
 
-       if (skb->len &&
-           (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
-            ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin))) {
+       if (ipv4_datagram_support_cmsg(sk, skb, serr->ee.ee_origin)) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
                if (inet_sk(sk)->cmsg_flags)
index 9d78427652d23e33a46ab7ce2d4b6dbac1660781..fe54eba6d00d3462c287b095370e3a938e73b178 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 99e810f84671bbdb80e33c6915cc7be49ba0f1bb..cf5e82f39d3b87d7f8163320bffbc26af38d6f98 100644 (file)
@@ -272,9 +272,9 @@ static void trace_packet(const struct sk_buff *skb,
                    &chainname, &comment, &rulenum) != 0)
                        break;
 
-       nf_log_packet(net, AF_INET, hook, skb, in, out, &trace_loginfo,
-                     "TRACE: %s:%s:%s:%u ",
-                     tablename, chainname, comment, rulenum);
+       nf_log_trace(net, AF_INET, hook, skb, in, out, &trace_loginfo,
+                    "TRACE: %s:%s:%s:%u ",
+                    tablename, chainname, comment, rulenum);
 }
 #endif
 
index e9f66e1cda507cf2d5cb532958d23a89beeccaba..208d5439e59b2e8c3ccb2da46c292ad4f75b3784 100644 (file)
@@ -259,6 +259,9 @@ int ping_init_sock(struct sock *sk)
        kgid_t low, high;
        int ret = 0;
 
+       if (sk->sk_family == AF_INET6)
+               sk->sk_ipv6only = 1;
+
        inet_get_ping_group_range_net(net, &low, &high);
        if (gid_lte(low, group) && gid_lte(group, high))
                return 0;
@@ -305,6 +308,11 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
                if (addr_len < sizeof(*addr))
                        return -EINVAL;
 
+               if (addr->sin_family != AF_INET &&
+                   !(addr->sin_family == AF_UNSPEC &&
+                     addr->sin_addr.s_addr == htonl(INADDR_ANY)))
+                       return -EAFNOSUPPORT;
+
                pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n",
                         sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
 
@@ -330,7 +338,7 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
                        return -EINVAL;
 
                if (addr->sin6_family != AF_INET6)
-                       return -EINVAL;
+                       return -EAFNOSUPPORT;
 
                pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n",
                         sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
@@ -716,7 +724,7 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
                if (msg->msg_namelen < sizeof(*usin))
                        return -EINVAL;
                if (usin->sin_family != AF_INET)
-                       return -EINVAL;
+                       return -EAFNOSUPPORT;
                daddr = usin->sin_addr.s_addr;
                /* no remote port */
        } else {
index 9d72a0fcd9284425e088cef6e1b8c14e95950ca4..995a2259bcfc80894caec08fe2e7ccd62311e227 100644 (file)
@@ -835,17 +835,13 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
                                       int large_allowed)
 {
        struct tcp_sock *tp = tcp_sk(sk);
-       u32 new_size_goal, size_goal, hlen;
+       u32 new_size_goal, size_goal;
 
        if (!large_allowed || !sk_can_gso(sk))
                return mss_now;
 
-       /* Maybe we should/could use sk->sk_prot->max_header here ? */
-       hlen = inet_csk(sk)->icsk_af_ops->net_header_len +
-              inet_csk(sk)->icsk_ext_hdr_len +
-              tp->tcp_header_len;
-
-       new_size_goal = sk->sk_gso_max_size - 1 - hlen;
+       /* Note : tcp_tso_autosize() will eventually split this later */
+       new_size_goal = sk->sk_gso_max_size - 1 - MAX_TCP_HEADER;
        new_size_goal = tcp_bound_to_half_wnd(tp, new_size_goal);
 
        /* We try hard to avoid divides here */
index d694088214cd87fa50e413730402499610c546e6..62856e185a935e44deb26de59ff94c8bf7500579 100644 (file)
@@ -378,6 +378,12 @@ EXPORT_SYMBOL_GPL(tcp_slow_start);
  */
 void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked)
 {
+       /* If credits accumulated at a higher w, apply them gently now. */
+       if (tp->snd_cwnd_cnt >= w) {
+               tp->snd_cwnd_cnt = 0;
+               tp->snd_cwnd++;
+       }
+
        tp->snd_cwnd_cnt += acked;
        if (tp->snd_cwnd_cnt >= w) {
                u32 delta = tp->snd_cwnd_cnt / w;
index 4b276d1ed9807057986bd3b050e2e901bf1afec0..06d3d665a9fd1bfda5688907a284de83697273f6 100644 (file)
@@ -306,8 +306,10 @@ tcp_friendliness:
                }
        }
 
-       if (ca->cnt == 0)                       /* cannot be zero */
-               ca->cnt = 1;
+       /* The maximum rate of cwnd increase CUBIC allows is 1 packet per
+        * 2 packets ACKed, meaning cwnd grows at 1.5x per RTT.
+        */
+       ca->cnt = max(ca->cnt, 2U);
 }
 
 static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
index 8fdd27b173061def484663beeace691a8bfa2365..f501ac0483665aeb1100e2f2776d3f38610e9b30 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 5a2dfed4783b6ed0185dccded960972b4d6e13b0..f1756ee022078d12e74be5d245fc1a6a0c1c4a34 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 a2a796c5536b032264e2a71f596f673e8307f25c..1db253e36045ac038d7449a06d312275535a8014 100644 (file)
@@ -2773,15 +2773,11 @@ void tcp_send_fin(struct sock *sk)
        } else {
                /* Socket is locked, keep trying until memory is available. */
                for (;;) {
-                       skb = alloc_skb_fclone(MAX_TCP_HEADER,
-                                              sk->sk_allocation);
+                       skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
                        if (skb)
                                break;
                        yield();
                }
-
-               /* Reserve space for headers and prepare control bits. */
-               skb_reserve(skb, MAX_TCP_HEADER);
                /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
                tcp_init_nondata_skb(skb, tp->write_seq,
                                     TCPHDR_ACK | TCPHDR_FIN);
index d5f6bd9a210ab93ed27177ecffc9499259dbe999..dab73813cb9208dafaae1277e281c2255601a771 100644 (file)
@@ -63,6 +63,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
+       skb->protocol = htons(ETH_P_IP);
 
        return x->outer_mode->output2(x, skb);
 }
@@ -71,7 +72,6 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
 int xfrm4_output_finish(struct sk_buff *skb)
 {
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-       skb->protocol = htons(ETH_P_IP);
 
 #ifdef CONFIG_NETFILTER
        IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
index 98e4a63d72bb435e1ac1ae7cf2767072eed6db92..b6030025f41197efbcdfd1d8c013e469413550b5 100644 (file)
@@ -4903,6 +4903,21 @@ int addrconf_sysctl_forward(struct ctl_table *ctl, int write,
        return ret;
 }
 
+static
+int addrconf_sysctl_mtu(struct ctl_table *ctl, int write,
+                       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct inet6_dev *idev = ctl->extra1;
+       int min_mtu = IPV6_MIN_MTU;
+       struct ctl_table lctl;
+
+       lctl = *ctl;
+       lctl.extra1 = &min_mtu;
+       lctl.extra2 = idev ? &idev->dev->mtu : NULL;
+
+       return proc_dointvec_minmax(&lctl, write, buffer, lenp, ppos);
+}
+
 static void dev_disable_change(struct inet6_dev *idev)
 {
        struct netdev_notifier_info info;
@@ -5054,7 +5069,7 @@ static struct addrconf_sysctl_table
                        .data           = &ipv6_devconf.mtu6,
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .proc_handler   = addrconf_sysctl_mtu,
                },
                {
                        .procname       = "accept_ra",
index c215be70cac08af78953ea860c5d67cf9d3fa642..ace8daca5c8361ad37073a4eeb0f8d55c622d807 100644 (file)
@@ -325,14 +325,34 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
        kfree_skb(skb);
 }
 
-static void ip6_datagram_prepare_pktinfo_errqueue(struct sk_buff *skb)
+/* IPv6 supports cmsg on all origins aside from SO_EE_ORIGIN_LOCAL.
+ *
+ * At one point, excluding local errors was a quick test to identify icmp/icmp6
+ * errors. This is no longer true, but the test remained, so the v6 stack,
+ * unlike v4, also honors cmsg requests on all wifi and timestamp errors.
+ *
+ * Timestamp code paths do not initialize the fields expected by cmsg:
+ * the PKTINFO fields in skb->cb[]. Fill those in here.
+ */
+static bool ip6_datagram_support_cmsg(struct sk_buff *skb,
+                                     struct sock_exterr_skb *serr)
 {
-       int ifindex = skb->dev ? skb->dev->ifindex : -1;
+       if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
+           serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6)
+               return true;
+
+       if (serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL)
+               return false;
+
+       if (!skb->dev)
+               return false;
 
        if (skb->protocol == htons(ETH_P_IPV6))
-               IP6CB(skb)->iif = ifindex;
+               IP6CB(skb)->iif = skb->dev->ifindex;
        else
-               PKTINFO_SKB_CB(skb)->ipi_ifindex = ifindex;
+               PKTINFO_SKB_CB(skb)->ipi_ifindex = skb->dev->ifindex;
+
+       return true;
 }
 
 /*
@@ -369,7 +389,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        serr = SKB_EXT_ERR(skb);
 
-       if (sin && skb->len) {
+       if (sin && serr->port) {
                const unsigned char *nh = skb_network_header(skb);
                sin->sin6_family = AF_INET6;
                sin->sin6_flowinfo = 0;
@@ -394,14 +414,11 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
        memset(sin, 0, sizeof(*sin));
-       if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL && skb->len) {
+
+       if (ip6_datagram_support_cmsg(skb, serr)) {
                sin->sin6_family = AF_INET6;
-               if (np->rxopt.all) {
-                       if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
-                           serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6)
-                               ip6_datagram_prepare_pktinfo_errqueue(skb);
+               if (np->rxopt.all)
                        ip6_datagram_recv_common_ctl(sk, msg, skb);
-               }
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        sin->sin6_addr = ipv6_hdr(skb)->saddr;
                        if (np->rxopt.all)
index b4d5e1d97c1b2576fc02a15b7a05a773197bb8e0..70bc6abc0639cf88d0b23b295c20d941b456d98b 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 7deebf102cbafc276f45e4eaffdd8efdb658d842..36cf0ab685a00d57fbdc6787ba77116dae638f21 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 266a264ec21273147b32d75ac7bde55afdd1b4cf..ddd94eca19b3986e4fc0b1ff684eee401032815e 100644 (file)
@@ -314,7 +314,7 @@ out:
  *   Create tunnel matching given parameters.
  *
  * Return:
- *   created tunnel or NULL
+ *   created tunnel or error pointer
  **/
 
 static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
@@ -322,7 +322,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
        struct net_device *dev;
        struct ip6_tnl *t;
        char name[IFNAMSIZ];
-       int err;
+       int err = -ENOMEM;
 
        if (p->name[0])
                strlcpy(name, p->name, IFNAMSIZ);
@@ -348,7 +348,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
 failed_free:
        ip6_dev_free(dev);
 failed:
-       return NULL;
+       return ERR_PTR(err);
 }
 
 /**
@@ -362,7 +362,7 @@ failed:
  *   tunnel device is created and registered for use.
  *
  * Return:
- *   matching tunnel or NULL
+ *   matching tunnel or error pointer
  **/
 
 static struct ip6_tnl *ip6_tnl_locate(struct net *net,
@@ -380,13 +380,13 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net,
                if (ipv6_addr_equal(local, &t->parms.laddr) &&
                    ipv6_addr_equal(remote, &t->parms.raddr)) {
                        if (create)
-                               return NULL;
+                               return ERR_PTR(-EEXIST);
 
                        return t;
                }
        }
        if (!create)
-               return NULL;
+               return ERR_PTR(-ENODEV);
        return ip6_tnl_create(net, p);
 }
 
@@ -1420,7 +1420,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        }
                        ip6_tnl_parm_from_user(&p1, &p);
                        t = ip6_tnl_locate(net, &p1, 0);
-                       if (t == NULL)
+                       if (IS_ERR(t))
                                t = netdev_priv(dev);
                } else {
                        memset(&p, 0, sizeof(p));
@@ -1445,7 +1445,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                ip6_tnl_parm_from_user(&p1, &p);
                t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
                if (cmd == SIOCCHGTUNNEL) {
-                       if (t != NULL) {
+                       if (!IS_ERR(t)) {
                                if (t->dev != dev) {
                                        err = -EEXIST;
                                        break;
@@ -1457,14 +1457,15 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        else
                                err = ip6_tnl_update(t, &p1);
                }
-               if (t) {
+               if (!IS_ERR(t)) {
                        err = 0;
                        ip6_tnl_parm_to_user(&p, &t->parms);
                        if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
                                err = -EFAULT;
 
-               } else
-                       err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+               } else {
+                       err = PTR_ERR(t);
+               }
                break;
        case SIOCDELTUNNEL:
                err = -EPERM;
@@ -1478,7 +1479,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        err = -ENOENT;
                        ip6_tnl_parm_from_user(&p1, &p);
                        t = ip6_tnl_locate(net, &p1, 0);
-                       if (t == NULL)
+                       if (IS_ERR(t))
                                break;
                        err = -EPERM;
                        if (t->dev == ip6n->fb_tnl_dev)
@@ -1672,12 +1673,13 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
                           struct nlattr *tb[], struct nlattr *data[])
 {
        struct net *net = dev_net(dev);
-       struct ip6_tnl *nt;
+       struct ip6_tnl *nt, *t;
 
        nt = netdev_priv(dev);
        ip6_tnl_netlink_parms(data, &nt->parms);
 
-       if (ip6_tnl_locate(net, &nt->parms, 0))
+       t = ip6_tnl_locate(net, &nt->parms, 0);
+       if (!IS_ERR(t))
                return -EEXIST;
 
        return ip6_tnl_create2(dev);
@@ -1697,8 +1699,7 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
        ip6_tnl_netlink_parms(data, &p);
 
        t = ip6_tnl_locate(net, &p, 0);
-
-       if (t) {
+       if (!IS_ERR(t)) {
                if (t->dev != dev)
                        return -EEXIST;
        } else
index 34b682617f504359cecff4447c6015f90623e949..312e0ff47339be3a3ffa8981c9e1b1cb7f5a551b 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 471ed24aabaec4b1d8736438696ca3490d4e0f58..14ecdaf06bf7497dc71199fc5638b49592a24655 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 e080fbbbc0e5ce8d4d71014eed149e6b34250b62..bb00c6f2a8855fb72dcc6a1bc5b496e8216d683f 100644 (file)
@@ -298,9 +298,9 @@ static void trace_packet(const struct sk_buff *skb,
                    &chainname, &comment, &rulenum) != 0)
                        break;
 
-       nf_log_packet(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
-                     "TRACE: %s:%s:%s:%u ",
-                     tablename, chainname, comment, rulenum);
+       nf_log_trace(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
+                    "TRACE: %s:%s:%s:%u ",
+                    tablename, chainname, comment, rulenum);
 }
 #endif
 
index bd46f736f61d74bcb75a4dabef264154f55a9fb0..a2dfff6ff227e09607d1d267265e7635d64a2030 100644 (file)
@@ -102,9 +102,10 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        if (msg->msg_name) {
                DECLARE_SOCKADDR(struct sockaddr_in6 *, u, msg->msg_name);
-               if (msg->msg_namelen < sizeof(struct sockaddr_in6) ||
-                   u->sin6_family != AF_INET6) {
+               if (msg->msg_namelen < sizeof(*u))
                        return -EINVAL;
+               if (u->sin6_family != AF_INET6) {
+                       return -EAFNOSUPPORT;
                }
                if (sk->sk_bound_dev_if &&
                    sk->sk_bound_dev_if != u->sin6_scope_id) {
index 5d46832c6f72b89a278a3326918a3c8bff9afed4..1f5e62229aaa8b4d5822f82c3af3a6c8b1382ba6 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 ab889bb16b3cb077d26ddd2837b8b2eaaf1de666..be2c0ba82c8525ca466468ae45b05df5b35f85b6 100644 (file)
@@ -112,11 +112,9 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
                fptr->nexthdr = nexthdr;
                fptr->reserved = 0;
-               if (skb_shinfo(skb)->ip6_frag_id)
-                       fptr->identification = skb_shinfo(skb)->ip6_frag_id;
-               else
-                       ipv6_select_ident(fptr,
-                                         (struct rt6_info *)skb_dst(skb));
+               if (!skb_shinfo(skb)->ip6_frag_id)
+                       ipv6_proxy_select_ident(skb);
+               fptr->identification = skb_shinfo(skb)->ip6_frag_id;
 
                /* Fragment the skb. ipv6 header and the remaining fields of the
                 * fragment header are updated in ipv6_gso_segment()
index ca3f29b98ae5d76b7e69c38f617362a90fd9fd04..010f8bd2d577f9767d7d44182b246e62f4a118f6 100644 (file)
@@ -114,6 +114,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        skb->ignore_df = 1;
+       skb->protocol = htons(ETH_P_IPV6);
 
        return x->outer_mode->output2(x, skb);
 }
@@ -122,7 +123,6 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
 int xfrm6_output_finish(struct sk_buff *skb)
 {
        memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
-       skb->protocol = htons(ETH_P_IPV6);
 
 #ifdef CONFIG_NETFILTER
        IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
index 48bf5a06847bd59db7834758b22aa9208d727940..8d2d01b4800a197eaaa64fb184f56c58920ad462 100644 (file)
@@ -200,6 +200,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
 
 #if IS_ENABLED(CONFIG_IPV6_MIP6)
                case IPPROTO_MH:
+                       offset += ipv6_optlen(exthdr);
                        if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
                                struct ip6_mh *mh;
 
index 40695b9751c10b41e7fd310fa5d15bcef4629549..683346d2d633b4b2ac839e975e2c21d687242075 100644 (file)
@@ -798,7 +798,9 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
        orig_jiffies = jiffies;
 
        /* Set poll time to 200 ms */
-       poll_time = IRDA_MIN(timeout, msecs_to_jiffies(200));
+       poll_time = msecs_to_jiffies(200);
+       if (timeout)
+               poll_time = min_t(unsigned long, timeout, poll_time);
 
        spin_lock_irqsave(&self->spinlock, flags);
        while (self->tx_skb && self->tx_skb->len) {
@@ -811,7 +813,7 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
                        break;
        }
        spin_unlock_irqrestore(&self->spinlock, flags);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
 }
 
 /*
index 3c83a1e5ab0394f0eaa04b4ba5a813d118c17434..1215693fdd22897b5217b878763d56d087a25372 100644 (file)
@@ -305,7 +305,7 @@ irnet_ctrl_read(irnet_socket *      ap,
 
   /* Put ourselves on the wait queue to be woken up */
   add_wait_queue(&irnet_events.rwait, &wait);
-  current->state = TASK_INTERRUPTIBLE;
+  set_current_state(TASK_INTERRUPTIBLE);
   for(;;)
     {
       /* If there is unread events */
@@ -321,7 +321,7 @@ irnet_ctrl_read(irnet_socket *      ap,
       /* Yield and wait to be woken up */
       schedule();
     }
-  current->state = TASK_RUNNING;
+  __set_current_state(TASK_RUNNING);
   remove_wait_queue(&irnet_events.rwait, &wait);
 
   /* Did we got it ? */
index 2e9953b2db8402dd71c88691f263db00f2cba3e2..53d931172088b15b2890c42dd649308771b6e7d3 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 895348e44c7d22c9e6d4828195e7099a74154531..a29a504492af6f2c38607f2c15e123a297d565cd 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 a48bad468880aa60c80b45a1cc97bef616845ffa..7702978a4c999dfd10d9b49792b8b25899e23966 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 ff0d2db09df9db467a5831606971e02f2fe6d410..5bcd4e5589d3294602c4abdeff778497afbc8de1 100644 (file)
@@ -1508,6 +1508,8 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
        if (ieee80211_chanctx_refcount(local, ctx) == 0)
                ieee80211_free_chanctx(local, ctx);
 
+       sdata->radar_required = false;
+
        /* Unreserving may ready an in-place reservation. */
        if (use_reserved_switch)
                ieee80211_vif_use_reserved_switch(local);
@@ -1566,6 +1568,9 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_smps_chanctx(local, ctx);
        ieee80211_recalc_radar_chanctx(local, ctx);
  out:
+       if (ret)
+               sdata->radar_required = false;
+
        mutex_unlock(&local->chanctx_mtx);
        return ret;
 }
index 3afe36824703f49dcfe374e103b6372a9851b8aa..8d53d65bd2abc2d993ae5dbc7df37b707fd9ec13 100644 (file)
@@ -58,13 +58,24 @@ struct ieee80211_local;
 #define IEEE80211_UNSET_POWER_LEVEL    INT_MIN
 
 /*
- * Some APs experience problems when working with U-APSD. Decrease the
- * probability of that happening by using legacy mode for all ACs but VO.
- * The AP that caused us trouble was a Cisco 4410N. It ignores our
- * setting, and always treats non-VO ACs as legacy.
+ * Some APs experience problems when working with U-APSD. Decreasing the
+ * probability of that happening by using legacy mode for all ACs but VO isn't
+ * enough.
+ *
+ * Cisco 4410N originally forced us to enable VO by default only because it
+ * treated non-VO ACs as legacy.
+ *
+ * However some APs (notably Netgear R7000) silently reclassify packets to
+ * different ACs. Since u-APSD ACs require trigger frames for frame retrieval
+ * clients would never see some frames (e.g. ARP responses) or would fetch them
+ * accidentally after a long time.
+ *
+ * It makes little sense to enable u-APSD queues by default because it needs
+ * userspace applications to be aware of it to actually take advantage of the
+ * possible additional powersavings. Implicitly depending on driver autotrigger
+ * frame support doesn't make much sense.
  */
-#define IEEE80211_DEFAULT_UAPSD_QUEUES \
-       IEEE80211_WMM_IE_STA_QOSINFO_AC_VO
+#define IEEE80211_DEFAULT_UAPSD_QUEUES 0
 
 #define IEEE80211_DEFAULT_MAX_SP_LEN           \
        IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
@@ -453,6 +464,7 @@ struct ieee80211_if_managed {
        unsigned int flags;
 
        bool csa_waiting_bcn;
+       bool csa_ignored_same_chan;
 
        bool beacon_crc_valid;
        u32 beacon_crc;
index 10ac6324c1d014c708749748ce89ef31055561cf..142f66aece18a8789205fc12b0e1d7c7816d0863 100644 (file)
@@ -1150,6 +1150,17 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
+       if (cfg80211_chandef_identical(&csa_ie.chandef,
+                                      &sdata->vif.bss_conf.chandef)) {
+               if (ifmgd->csa_ignored_same_chan)
+                       return;
+               sdata_info(sdata,
+                          "AP %pM tries to chanswitch to same channel, ignore\n",
+                          ifmgd->associated->bssid);
+               ifmgd->csa_ignored_same_chan = true;
+               return;
+       }
+
        mutex_lock(&local->mtx);
        mutex_lock(&local->chanctx_mtx);
        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
@@ -1210,6 +1221,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        sdata->vif.csa_active = true;
        sdata->csa_chandef = csa_ie.chandef;
        sdata->csa_block_tx = csa_ie.mode;
+       ifmgd->csa_ignored_same_chan = false;
 
        if (sdata->csa_block_tx)
                ieee80211_stop_vif_queues(local, sdata,
@@ -2090,6 +2102,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        sdata->vif.csa_active = false;
        ifmgd->csa_waiting_bcn = false;
+       ifmgd->csa_ignored_same_chan = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3204,7 +3217,8 @@ static const u64 care_about_ies =
        (1ULL << WLAN_EID_CHANNEL_SWITCH) |
        (1ULL << WLAN_EID_PWR_CONSTRAINT) |
        (1ULL << WLAN_EID_HT_CAPABILITY) |
-       (1ULL << WLAN_EID_HT_OPERATION);
+       (1ULL << WLAN_EID_HT_OPERATION) |
+       (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN);
 
 static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt, size_t len,
index 7c86a002df95fee46be8e7dfdb0d691fff0e9e7f..ef6e8a6c4253c72f6f2398b733e8c427f5b59953 100644 (file)
@@ -373,7 +373,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                rate++;
                mi->sample_deferred++;
        } else {
-               if (!msr->sample_limit != 0)
+               if (!msr->sample_limit)
                        return;
 
                mi->sample_packets++;
index 1101563357eae365f1e1a1df926ecf36fdc0570b..1eb730bf875272831d44ac62c6e5a18e0a1de977 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 925e68fe64c755766c2ecc30d047455f62c11362..fb0fc1302a588480cae6649e2e671ffa719de36b 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 88a18ffe2975520edbcc80733bc1bbc9b2655f11..07bd8db00af84b820139c644da95eaf29e474b5f 100644 (file)
@@ -566,6 +566,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
                if (tx->sdata->control_port_no_encrypt)
                        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
                info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
+               info->flags |= IEEE80211_TX_CTL_USE_MINRATE;
        }
 
        return TX_CONTINUE;
index 8428f4a954795657a32a24f77a0f9c9ae6591b7e..747bdcf72e92788574ec3e2e635b5e6b96cb75f0 100644 (file)
@@ -3178,7 +3178,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
                wdev_iter = &sdata_iter->wdev;
 
                if (sdata_iter == sdata ||
-                   rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
+                   !ieee80211_sdata_running(sdata_iter) ||
                    local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
                        continue;
 
index e55759056361c47ed1fcfa5c656541ba39bfd260..ed99448671c3003374fc947bee6e91ab0f0d3fce 100644 (file)
@@ -3402,7 +3402,7 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
                if (udest.af == 0)
                        udest.af = svc->af;
 
-               if (udest.af != svc->af) {
+               if (udest.af != svc->af && cmd != IPVS_CMD_DEL_DEST) {
                        /* The synchronization protocol is incompatible
                         * with mixed family services
                         */
index c47ffd7a0a709cb73834c84652f251960f25db79..d93ceeb3ef04822427004ef0a70549f389d17354 100644 (file)
@@ -896,6 +896,8 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param,
                        IP_VS_DBG(2, "BACKUP, add new conn. failed\n");
                        return;
                }
+               if (!(flags & IP_VS_CONN_F_TEMPLATE))
+                       kfree(param->pe_data);
        }
 
        if (opt)
@@ -1169,6 +1171,7 @@ static inline int ip_vs_proc_sync_conn(struct net *net, __u8 *p, __u8 *msg_end)
                                (opt_flags & IPVS_OPT_F_SEQ_DATA ? &opt : NULL)
                                );
 #endif
+       ip_vs_pe_put(param.pe);
        return 0;
        /* Error exit */
 out:
index 0d8448f19dfe982f64879d9dc55ba7d746696196..675d12c69e325c70e46ca5e5522fb5f8c77b7d8b 100644 (file)
@@ -212,6 +212,30 @@ void nf_log_packet(struct net *net,
 }
 EXPORT_SYMBOL(nf_log_packet);
 
+void nf_log_trace(struct net *net,
+                 u_int8_t pf,
+                 unsigned int hooknum,
+                 const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct nf_loginfo *loginfo, const char *fmt, ...)
+{
+       va_list args;
+       char prefix[NF_LOG_PREFIXLEN];
+       const struct nf_logger *logger;
+
+       rcu_read_lock();
+       logger = rcu_dereference(net->nf.nf_loggers[pf]);
+       if (logger) {
+               va_start(args, fmt);
+               vsnprintf(prefix, sizeof(prefix), fmt, args);
+               va_end(args);
+               logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(nf_log_trace);
+
 #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
 
 struct nf_log_buf {
index 199fd0f27b0e128cfb8674ca331c2dae240e1b1c..ac1a9528dbf2e4af0d33fec5667369d23ed179e4 100644 (file)
@@ -227,7 +227,7 @@ nft_rule_deactivate_next(struct net *net, struct nft_rule *rule)
 
 static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
 {
-       rule->genmask = 0;
+       rule->genmask &= ~(1 << gencursor_next(net));
 }
 
 static int
@@ -1225,7 +1225,10 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 
        if (nla[NFTA_CHAIN_POLICY]) {
                if ((chain != NULL &&
-                   !(chain->flags & NFT_BASE_CHAIN)) ||
+                   !(chain->flags & NFT_BASE_CHAIN)))
+                       return -EOPNOTSUPP;
+
+               if (chain == NULL &&
                    nla[NFTA_CHAIN_HOOK] == NULL)
                        return -EOPNOTSUPP;
 
@@ -1711,9 +1714,12 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
        }
        nla_nest_end(skb, list);
 
-       if (rule->ulen &&
-           nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule)))
-               goto nla_put_failure;
+       if (rule->udata) {
+               struct nft_userdata *udata = nft_userdata(rule);
+               if (nla_put(skb, NFTA_RULE_USERDATA, udata->len + 1,
+                           udata->data) < 0)
+                       goto nla_put_failure;
+       }
 
        nlmsg_end(skb, nlh);
        return 0;
@@ -1896,11 +1902,12 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
        struct nft_table *table;
        struct nft_chain *chain;
        struct nft_rule *rule, *old_rule = NULL;
+       struct nft_userdata *udata;
        struct nft_trans *trans = NULL;
        struct nft_expr *expr;
        struct nft_ctx ctx;
        struct nlattr *tmp;
-       unsigned int size, i, n, ulen = 0;
+       unsigned int size, i, n, ulen = 0, usize = 0;
        int err, rem;
        bool create;
        u64 handle, pos_handle;
@@ -1968,12 +1975,19 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
                        n++;
                }
        }
+       /* Check for overflow of dlen field */
+       err = -EFBIG;
+       if (size >= 1 << 12)
+               goto err1;
 
-       if (nla[NFTA_RULE_USERDATA])
+       if (nla[NFTA_RULE_USERDATA]) {
                ulen = nla_len(nla[NFTA_RULE_USERDATA]);
+               if (ulen > 0)
+                       usize = sizeof(struct nft_userdata) + ulen;
+       }
 
        err = -ENOMEM;
-       rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL);
+       rule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL);
        if (rule == NULL)
                goto err1;
 
@@ -1981,10 +1995,13 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
        rule->handle = handle;
        rule->dlen   = size;
-       rule->ulen   = ulen;
+       rule->udata  = ulen ? 1 : 0;
 
-       if (ulen)
-               nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen);
+       if (ulen) {
+               udata = nft_userdata(rule);
+               udata->len = ulen - 1;
+               nla_memcpy(udata->data, nla[NFTA_RULE_USERDATA], ulen);
+       }
 
        expr = nft_expr_first(rule);
        for (i = 0; i < n; i++) {
@@ -2031,12 +2048,6 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
 err3:
        list_del_rcu(&rule->list);
-       if (trans) {
-               list_del_rcu(&nft_trans_rule(trans)->list);
-               nft_rule_clear(net, nft_trans_rule(trans));
-               nft_trans_destroy(trans);
-               chain->use++;
-       }
 err2:
        nf_tables_rule_destroy(&ctx, rule);
 err1:
@@ -3612,12 +3623,11 @@ static int nf_tables_commit(struct sk_buff *skb)
                                                 &te->elem,
                                                 NFT_MSG_DELSETELEM, 0);
                        te->set->ops->get(te->set, &te->elem);
-                       te->set->ops->remove(te->set, &te->elem);
                        nft_data_uninit(&te->elem.key, NFT_DATA_VALUE);
-                       if (te->elem.flags & NFT_SET_MAP) {
-                               nft_data_uninit(&te->elem.data,
-                                               te->set->dtype);
-                       }
+                       if (te->set->flags & NFT_SET_MAP &&
+                           !(te->elem.flags & NFT_SET_ELEM_INTERVAL_END))
+                               nft_data_uninit(&te->elem.data, te->set->dtype);
+                       te->set->ops->remove(te->set, &te->elem);
                        nft_trans_destroy(trans);
                        break;
                }
@@ -3658,7 +3668,7 @@ static int nf_tables_abort(struct sk_buff *skb)
 {
        struct net *net = sock_net(skb->sk);
        struct nft_trans *trans, *next;
-       struct nft_set *set;
+       struct nft_trans_elem *te;
 
        list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
                switch (trans->msg_type) {
@@ -3719,9 +3729,13 @@ static int nf_tables_abort(struct sk_buff *skb)
                        break;
                case NFT_MSG_NEWSETELEM:
                        nft_trans_elem_set(trans)->nelems--;
-                       set = nft_trans_elem_set(trans);
-                       set->ops->get(set, &nft_trans_elem(trans));
-                       set->ops->remove(set, &nft_trans_elem(trans));
+                       te = (struct nft_trans_elem *)trans->data;
+                       te->set->ops->get(te->set, &te->elem);
+                       nft_data_uninit(&te->elem.key, NFT_DATA_VALUE);
+                       if (te->set->flags & NFT_SET_MAP &&
+                           !(te->elem.flags & NFT_SET_ELEM_INTERVAL_END))
+                               nft_data_uninit(&te->elem.data, te->set->dtype);
+                       te->set->ops->remove(te->set, &te->elem);
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELSETELEM:
index 3b90eb2b2c55453e989c891a3f815be6e1da22d1..2d298dccb6dd3fc5589be16021c843d741a4c025 100644 (file)
@@ -94,10 +94,10 @@ static void nft_trace_packet(const struct nft_pktinfo *pkt,
 {
        struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
 
-       nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
-                     pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
-                     chain->table->name, chain->name, comments[type],
-                     rulenum);
+       nf_log_trace(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
+                    pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
+                    chain->table->name, chain->name, comments[type],
+                    rulenum);
 }
 
 unsigned int
index a5599fc51a6f3f87db4d63ecd20073481520a238..54330fb5efaf632d39d3e00135ac3360bdfdb80d 100644 (file)
@@ -77,6 +77,9 @@ nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
        if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
                return -EINVAL;
 
+       /* Not all fields are initialized so first zero the tuple */
+       memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
+
        tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
        tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
 
index c598f74063a19ebd51ea786530c0669d6f92b8c3..65f3e2b6be44031448d85323ccf17cddaffd5557 100644 (file)
@@ -123,7 +123,7 @@ static void
 nft_target_set_tgchk_param(struct xt_tgchk_param *par,
                           const struct nft_ctx *ctx,
                           struct xt_target *target, void *info,
-                          union nft_entry *entry, u8 proto, bool inv)
+                          union nft_entry *entry, u16 proto, bool inv)
 {
        par->net        = ctx->net;
        par->table      = ctx->table->name;
@@ -133,11 +133,14 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
                break;
        case AF_INET6:
+               if (proto)
+                       entry->e6.ipv6.flags |= IP6T_F_PROTO;
+
                entry->e6.ipv6.proto = proto;
                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
                break;
        case NFPROTO_BRIDGE:
-               entry->ebt.ethproto = proto;
+               entry->ebt.ethproto = (__force __be16)proto;
                entry->ebt.invflags = inv ? EBT_IPROTO : 0;
                break;
        }
@@ -171,7 +174,7 @@ static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1]
        [NFTA_RULE_COMPAT_FLAGS]        = { .type = NLA_U32 },
 };
 
-static int nft_parse_compat(const struct nlattr *attr, u8 *proto, bool *inv)
+static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)
 {
        struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
        u32 flags;
@@ -203,7 +206,7 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        struct xt_target *target = expr->ops->data;
        struct xt_tgchk_param par;
        size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
-       u8 proto = 0;
+       u16 proto = 0;
        bool inv = false;
        union nft_entry e = {};
        int ret;
@@ -334,7 +337,7 @@ static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
 static void
 nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
                          struct xt_match *match, void *info,
-                         union nft_entry *entry, u8 proto, bool inv)
+                         union nft_entry *entry, u16 proto, bool inv)
 {
        par->net        = ctx->net;
        par->table      = ctx->table->name;
@@ -344,11 +347,14 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
                break;
        case AF_INET6:
+               if (proto)
+                       entry->e6.ipv6.flags |= IP6T_F_PROTO;
+
                entry->e6.ipv6.proto = proto;
                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
                break;
        case NFPROTO_BRIDGE:
-               entry->ebt.ethproto = proto;
+               entry->ebt.ethproto = (__force __be16)proto;
                entry->ebt.invflags = inv ? EBT_IPROTO : 0;
                break;
        }
@@ -385,7 +391,7 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        struct xt_match *match = expr->ops->data;
        struct xt_mtchk_param par;
        size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
-       u8 proto = 0;
+       u16 proto = 0;
        bool inv = false;
        union nft_entry e = {};
        int ret;
@@ -625,8 +631,12 @@ nft_match_select_ops(const struct nft_ctx *ctx,
                struct xt_match *match = nft_match->ops.data;
 
                if (strcmp(match->name, mt_name) == 0 &&
-                   match->revision == rev && match->family == family)
+                   match->revision == rev && match->family == family) {
+                       if (!try_module_get(match->me))
+                               return ERR_PTR(-ENOENT);
+
                        return &nft_match->ops;
+               }
        }
 
        match = xt_request_find_match(family, mt_name, rev);
@@ -695,8 +705,12 @@ nft_target_select_ops(const struct nft_ctx *ctx,
                struct xt_target *target = nft_target->ops.data;
 
                if (strcmp(target->name, tg_name) == 0 &&
-                   target->revision == rev && target->family == family)
+                   target->revision == rev && target->family == family) {
+                       if (!try_module_get(target->me))
+                               return ERR_PTR(-ENOENT);
+
                        return &nft_target->ops;
+               }
        }
 
        target = xt_request_find_target(family, tg_name, rev);
index 61e6c407476a618df386c2f14839033398aae14b..37c15e6748841053df56fe092a49ced6fb06b077 100644 (file)
@@ -153,6 +153,8 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
                                iter->err = err;
                                goto out;
                        }
+
+                       continue;
                }
 
                if (iter->count < iter->skip)
@@ -192,8 +194,6 @@ static int nft_hash_init(const struct nft_set *set,
                .key_offset = offsetof(struct nft_hash_elem, key),
                .key_len = set->klen,
                .hashfn = jhash,
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        return rhashtable_init(priv, &params);
index ef8a926752a97542f6f2f8eeb378e150958bff3d..50e1e5aaf4ce82ff7bbf1ee7171aaa51d54eefd1 100644 (file)
@@ -513,8 +513,8 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct ip6t_ip6 *i = par->entryinfo;
 
-       if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
-           && !(i->flags & IP6T_INV_PROTO))
+       if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) &&
+           !(i->invflags & IP6T_INV_PROTO))
                return 0;
 
        pr_info("Can be used only in combination with "
index 30dbe34915ae2b1fcf4d0ca3149369bdf3913f0f..45e1b30e4fb214f850af2590425ab2a9748c6476 100644 (file)
@@ -378,12 +378,11 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
        mutex_lock(&recent_mutex);
        t = recent_table_lookup(recent_net, info->name);
        if (t != NULL) {
-               if (info->hit_count > t->nstamps_max_mask) {
-                       pr_info("hitcount (%u) is larger than packets to be remembered (%u) for table %s\n",
-                               info->hit_count, t->nstamps_max_mask + 1,
-                               info->name);
-                       ret = -EINVAL;
-                       goto out;
+               if (nstamp_mask > t->nstamps_max_mask) {
+                       spin_lock_bh(&recent_lock);
+                       recent_table_flush(t);
+                       t->nstamps_max_mask = nstamp_mask;
+                       spin_unlock_bh(&recent_lock);
                }
 
                t->refcnt++;
index 1ba67931eb1b168fabfa78790f5ed53713188f9d..13332dbf291d6e530b77c3c8a7d155a07788ebc3 100644 (file)
@@ -243,12 +243,13 @@ static int
 extract_icmp6_fields(const struct sk_buff *skb,
                     unsigned int outside_hdrlen,
                     int *protocol,
-                    struct in6_addr **raddr,
-                    struct in6_addr **laddr,
+                    const struct in6_addr **raddr,
+                    const struct in6_addr **laddr,
                     __be16 *rport,
-                    __be16 *lport)
+                    __be16 *lport,
+                    struct ipv6hdr *ipv6_var)
 {
-       struct ipv6hdr *inside_iph, _inside_iph;
+       const struct ipv6hdr *inside_iph;
        struct icmp6hdr *icmph, _icmph;
        __be16 *ports, _ports[2];
        u8 inside_nexthdr;
@@ -263,12 +264,14 @@ extract_icmp6_fields(const struct sk_buff *skb,
        if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
                return 1;
 
-       inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph), &_inside_iph);
+       inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph),
+                                       sizeof(*ipv6_var), ipv6_var);
        if (inside_iph == NULL)
                return 1;
        inside_nexthdr = inside_iph->nexthdr;
 
-       inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph),
+       inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) +
+                                             sizeof(*ipv6_var),
                                         &inside_nexthdr, &inside_fragoff);
        if (inside_hdrlen < 0)
                return 1; /* hjm: Packet has no/incomplete transport layer headers. */
@@ -315,10 +318,10 @@ xt_socket_get_sock_v6(struct net *net, const u8 protocol,
 static bool
 socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 {
-       struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct ipv6hdr ipv6_var, *iph = ipv6_hdr(skb);
        struct udphdr _hdr, *hp = NULL;
        struct sock *sk = skb->sk;
-       struct in6_addr *daddr = NULL, *saddr = NULL;
+       const struct in6_addr *daddr = NULL, *saddr = NULL;
        __be16 uninitialized_var(dport), uninitialized_var(sport);
        int thoff = 0, uninitialized_var(tproto);
        const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
@@ -342,7 +345,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 
        } else if (tproto == IPPROTO_ICMPV6) {
                if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
-                                        &sport, &dport))
+                                        &sport, &dport, &ipv6_var))
                        return false;
        } else {
                return false;
index 2702673f0f237d7fa43e4649ccc0672f67c895bc..05919bf3f670ed1267e01f14c1de61e78e4d80c4 100644 (file)
@@ -3126,8 +3126,6 @@ static int __init netlink_proto_init(void)
                .key_len = sizeof(u32), /* portid */
                .hashfn = jhash,
                .max_shift = 16, /* 64K */
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        if (err != 0)
index ae5e77cdc0ca1f34ff7f9c99d65ba0c8bda9ace6..5bae7243c5777e38df7be95454b8164724c769cf 100644 (file)
@@ -2194,14 +2194,55 @@ static int __net_init ovs_init_net(struct net *net)
        return 0;
 }
 
-static void __net_exit ovs_exit_net(struct net *net)
+static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
+                                           struct list_head *head)
 {
-       struct datapath *dp, *dp_next;
        struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
+       struct datapath *dp;
+
+       list_for_each_entry(dp, &ovs_net->dps, list_node) {
+               int i;
+
+               for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
+                       struct vport *vport;
+
+                       hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) {
+                               struct netdev_vport *netdev_vport;
+
+                               if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL)
+                                       continue;
+
+                               netdev_vport = netdev_vport_priv(vport);
+                               if (dev_net(netdev_vport->dev) == dnet)
+                                       list_add(&vport->detach_list, head);
+                       }
+               }
+       }
+}
+
+static void __net_exit ovs_exit_net(struct net *dnet)
+{
+       struct datapath *dp, *dp_next;
+       struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id);
+       struct vport *vport, *vport_next;
+       struct net *net;
+       LIST_HEAD(head);
 
        ovs_lock();
        list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
                __dp_destroy(dp);
+
+       rtnl_lock();
+       for_each_net(net)
+               list_vports_from_net(net, dnet, &head);
+       rtnl_unlock();
+
+       /* Detach all vports from given namespace. */
+       list_for_each_entry_safe(vport, vport_next, &head, detach_list) {
+               list_del(&vport->detach_list);
+               ovs_dp_detach_port(vport);
+       }
+
        ovs_unlock();
 
        cancel_work_sync(&ovs_net->dp_notify_work);
index 216f20b90aa596b49592beee89a996cbe868d8ba..22b18c145c9221675e031de2617fcdd800405170 100644 (file)
@@ -2253,14 +2253,20 @@ static int masked_set_action_to_set_action_attr(const struct nlattr *a,
                                                struct sk_buff *skb)
 {
        const struct nlattr *ovs_key = nla_data(a);
+       struct nlattr *nla;
        size_t key_len = nla_len(ovs_key) / 2;
 
        /* Revert the conversion we did from a non-masked set action to
         * masked set action.
         */
-       if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a) - key_len, ovs_key))
+       nla = nla_nest_start(skb, OVS_ACTION_ATTR_SET);
+       if (!nla)
                return -EMSGSIZE;
 
+       if (nla_put(skb, nla_type(ovs_key), key_len, nla_data(ovs_key)))
+               return -EMSGSIZE;
+
+       nla_nest_end(skb, nla);
        return 0;
 }
 
index ec2954ffc690c612eb1b04b018134ba0f52ba5c8..067a3fff1d2cb0c629c1dc2d75d0353b9269ba71 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 f8ae295fb0011f7cc5dea75737833b7086641c77..bc85331a6c60cae9182bd1348d35d81117cf2943 100644 (file)
@@ -103,6 +103,7 @@ struct vport_portids {
  * @ops: Class structure.
  * @percpu_stats: Points to per-CPU statistics used and maintained by vport
  * @err_stats: Points to error statistics used and maintained by vport
+ * @detach_list: list used for detaching vport in net-exit call.
  */
 struct vport {
        struct rcu_head rcu;
@@ -117,6 +118,7 @@ struct vport {
        struct pcpu_sw_netstats __percpu *percpu_stats;
 
        struct vport_err_stats err_stats;
+       struct list_head detach_list;
 };
 
 /**
index 9c28cec1a0838ecf8ea03ceff77fb301c5a425a7..f8db7064d81c770cda356633153230eb905ccb39 100644 (file)
@@ -698,6 +698,10 @@ static void prb_retire_rx_blk_timer_expired(unsigned long data)
 
        if (pkc->last_kactive_blk_num == pkc->kactive_blk_num) {
                if (!frozen) {
+                       if (!BLOCK_NUM_PKTS(pbd)) {
+                               /* An empty block. Just refresh the timer. */
+                               goto refresh_timer;
+                       }
                        prb_retire_current_block(pkc, po, TP_STATUS_BLK_TMO);
                        if (!prb_dispatch_next_block(pkc, po))
                                goto refresh_timer;
@@ -798,7 +802,11 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
                h1->ts_last_pkt.ts_sec = last_pkt->tp_sec;
                h1->ts_last_pkt.ts_nsec = last_pkt->tp_nsec;
        } else {
-               /* Ok, we tmo'd - so get the current time */
+               /* Ok, we tmo'd - so get the current time.
+                *
+                * It shouldn't really happen as we don't close empty
+                * blocks. See prb_retire_rx_blk_timer_expired().
+                */
                struct timespec ts;
                getnstimeofday(&ts);
                h1->ts_last_pkt.ts_sec = ts.tv_sec;
@@ -1349,14 +1357,14 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
                return 0;
        }
 
+       if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
+               skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
+               if (!skb)
+                       return 0;
+       }
        switch (f->type) {
        case PACKET_FANOUT_HASH:
        default:
-               if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
-                       skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
-                       if (!skb)
-                               return 0;
-               }
                idx = fanout_demux_hash(f, skb, num);
                break;
        case PACKET_FANOUT_LB:
@@ -3115,11 +3123,18 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
        return 0;
 }
 
-static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what)
+static void packet_dev_mclist_delete(struct net_device *dev,
+                                    struct packet_mclist **mlp)
 {
-       for ( ; i; i = i->next) {
-               if (i->ifindex == dev->ifindex)
-                       packet_dev_mc(dev, i, what);
+       struct packet_mclist *ml;
+
+       while ((ml = *mlp) != NULL) {
+               if (ml->ifindex == dev->ifindex) {
+                       packet_dev_mc(dev, ml, -1);
+                       *mlp = ml->next;
+                       kfree(ml);
+               } else
+                       mlp = &ml->next;
        }
 }
 
@@ -3196,12 +3211,11 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq)
                                        packet_dev_mc(dev, ml, -1);
                                kfree(ml);
                        }
-                       rtnl_unlock();
-                       return 0;
+                       break;
                }
        }
        rtnl_unlock();
-       return -EADDRNOTAVAIL;
+       return 0;
 }
 
 static void packet_flush_mclist(struct sock *sk)
@@ -3551,7 +3565,7 @@ static int packet_notifier(struct notifier_block *this,
                switch (msg) {
                case NETDEV_UNREGISTER:
                        if (po->mclist)
-                               packet_dev_mclist(dev, po->mclist, -1);
+                               packet_dev_mclist_delete(dev, &po->mclist);
                        /* fallthrough */
 
                case NETDEV_DOWN:
index a817705ce2d0e9246388c2c65d77b4c486a8feba..dba8d0864f18046ee87a168d49cc159518fa2916 100644 (file)
@@ -88,7 +88,9 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
                        int *unpinned);
 static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
 
-static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id)
+static int rds_iw_get_device(struct sockaddr_in *src, struct sockaddr_in *dst,
+                            struct rds_iw_device **rds_iwdev,
+                            struct rdma_cm_id **cm_id)
 {
        struct rds_iw_device *iwdev;
        struct rds_iw_cm_id *i_cm_id;
@@ -112,15 +114,15 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
                                src_addr->sin_port,
                                dst_addr->sin_addr.s_addr,
                                dst_addr->sin_port,
-                               rs->rs_bound_addr,
-                               rs->rs_bound_port,
-                               rs->rs_conn_addr,
-                               rs->rs_conn_port);
+                               src->sin_addr.s_addr,
+                               src->sin_port,
+                               dst->sin_addr.s_addr,
+                               dst->sin_port);
 #ifdef WORKING_TUPLE_DETECTION
-                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr &&
-                           src_addr->sin_port == rs->rs_bound_port &&
-                           dst_addr->sin_addr.s_addr == rs->rs_conn_addr &&
-                           dst_addr->sin_port == rs->rs_conn_port) {
+                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr &&
+                           src_addr->sin_port == src->sin_port &&
+                           dst_addr->sin_addr.s_addr == dst->sin_addr.s_addr &&
+                           dst_addr->sin_port == dst->sin_port) {
 #else
                        /* FIXME - needs to compare the local and remote
                         * ipaddr/port tuple, but the ipaddr is the only
@@ -128,7 +130,7 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd
                         * zero'ed.  It doesn't appear to be properly populated
                         * during connection setup...
                         */
-                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr) {
+                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr) {
 #endif
                                spin_unlock_irq(&iwdev->spinlock);
                                *rds_iwdev = iwdev;
@@ -180,19 +182,13 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i
 {
        struct sockaddr_in *src_addr, *dst_addr;
        struct rds_iw_device *rds_iwdev_old;
-       struct rds_sock rs;
        struct rdma_cm_id *pcm_id;
        int rc;
 
        src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr;
        dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr;
 
-       rs.rs_bound_addr = src_addr->sin_addr.s_addr;
-       rs.rs_bound_port = src_addr->sin_port;
-       rs.rs_conn_addr = dst_addr->sin_addr.s_addr;
-       rs.rs_conn_port = dst_addr->sin_port;
-
-       rc = rds_iw_get_device(&rs, &rds_iwdev_old, &pcm_id);
+       rc = rds_iw_get_device(src_addr, dst_addr, &rds_iwdev_old, &pcm_id);
        if (rc)
                rds_iw_remove_cm_id(rds_iwdev, cm_id);
 
@@ -598,9 +594,17 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
        struct rds_iw_device *rds_iwdev;
        struct rds_iw_mr *ibmr = NULL;
        struct rdma_cm_id *cm_id;
+       struct sockaddr_in src = {
+               .sin_addr.s_addr = rs->rs_bound_addr,
+               .sin_port = rs->rs_bound_port,
+       };
+       struct sockaddr_in dst = {
+               .sin_addr.s_addr = rs->rs_conn_addr,
+               .sin_port = rs->rs_conn_port,
+       };
        int ret;
 
-       ret = rds_iw_get_device(rs, &rds_iwdev, &cm_id);
+       ret = rds_iw_get_device(&src, &dst, &rds_iwdev, &cm_id);
        if (ret || !cm_id) {
                ret = -ENODEV;
                goto out;
index c6be17a959a6e4981ecfff38af85805df6d8b26e..e0547f521f20d79c688c773286d609066c990a1d 100644 (file)
@@ -218,7 +218,8 @@ static void rxrpc_resend(struct rxrpc_call *call)
        struct rxrpc_header *hdr;
        struct sk_buff *txb;
        unsigned long *p_txb, resend_at;
-       int loop, stop;
+       bool stop;
+       int loop;
        u8 resend;
 
        _enter("{%d,%d,%d,%d},",
@@ -226,7 +227,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
               atomic_read(&call->sequence),
               CIRC_CNT(call->acks_head, call->acks_tail, call->acks_winsz));
 
-       stop = 0;
+       stop = false;
        resend = 0;
        resend_at = 0;
 
@@ -255,11 +256,11 @@ static void rxrpc_resend(struct rxrpc_call *call)
                        _proto("Tx DATA %%%u { #%d }",
                               ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
                        if (rxrpc_send_packet(call->conn->trans, txb) < 0) {
-                               stop = 0;
+                               stop = true;
                                sp->resend_at = jiffies + 3;
                        } else {
                                sp->resend_at =
-                                       jiffies + rxrpc_resend_timeout * HZ;
+                                       jiffies + rxrpc_resend_timeout;
                        }
                }
 
index 5394b6be46ecd5ebb6c677b745a4848977433f70..0610efa83d721389fc0f2c3597f3e284fee341d7 100644 (file)
@@ -42,7 +42,8 @@ void rxrpc_UDP_error_report(struct sock *sk)
                _leave("UDP socket errqueue empty");
                return;
        }
-       if (!skb->len) {
+       serr = SKB_EXT_ERR(skb);
+       if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
                _leave("UDP empty message");
                kfree_skb(skb);
                return;
@@ -50,7 +51,6 @@ void rxrpc_UDP_error_report(struct sock *sk)
 
        rxrpc_new_skb(skb);
 
-       serr = SKB_EXT_ERR(skb);
        addr = *(__be32 *)(skb_network_header(skb) + serr->addr_offset);
        port = serr->port;
 
index 4575485ad1b4d02796717879e09ad9078e232617..19a560626dc4f4232592e7d34381a859a04b6f4c 100644 (file)
@@ -87,7 +87,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (!skb) {
                        /* nothing remains on the queue */
                        if (copied &&
-                           (msg->msg_flags & MSG_PEEK || timeo == 0))
+                           (flags & MSG_PEEK || timeo == 0))
                                goto out;
 
                        /* wait for a message to turn up */
index 82c5d7fc19881577d888fad3d5b0369e4698172b..5f6288fa3f1247462897cd747364dfbc9e0da843 100644 (file)
@@ -25,21 +25,41 @@ static int tcf_bpf(struct sk_buff *skb, const struct tc_action *a,
                   struct tcf_result *res)
 {
        struct tcf_bpf *b = a->priv;
-       int action;
-       int filter_res;
+       int action, filter_res;
 
        spin_lock(&b->tcf_lock);
+
        b->tcf_tm.lastuse = jiffies;
        bstats_update(&b->tcf_bstats, skb);
-       action = b->tcf_action;
 
        filter_res = BPF_PROG_RUN(b->filter, skb);
-       if (filter_res == 0) {
-               /* Return code 0 from the BPF program
-                * is being interpreted as a drop here.
-                */
-               action = TC_ACT_SHOT;
+
+       /* A BPF program may overwrite the default action opcode.
+        * Similarly as in cls_bpf, if filter_res == -1 we use the
+        * default action specified from tc.
+        *
+        * In case a different well-known TC_ACT opcode has been
+        * returned, it will overwrite the default one.
+        *
+        * For everything else that is unkown, TC_ACT_UNSPEC is
+        * returned.
+        */
+       switch (filter_res) {
+       case TC_ACT_PIPE:
+       case TC_ACT_RECLASSIFY:
+       case TC_ACT_OK:
+               action = filter_res;
+               break;
+       case TC_ACT_SHOT:
+               action = filter_res;
                b->tcf_qstats.drops++;
+               break;
+       case TC_ACT_UNSPEC:
+               action = b->tcf_action;
+               break;
+       default:
+               action = TC_ACT_UNSPEC;
+               break;
        }
 
        spin_unlock(&b->tcf_lock);
index 09487afbfd5187a312ab155df5da43548d0c326b..95fdf4e4005190704dcd405e6b9422f8f56ba796 100644 (file)
@@ -78,8 +78,11 @@ struct tc_u_hnode {
        struct tc_u_common      *tp_c;
        int                     refcnt;
        unsigned int            divisor;
-       struct tc_u_knode __rcu *ht[1];
        struct rcu_head         rcu;
+       /* The 'ht' field MUST be the last field in structure to allow for
+        * more entries allocated at end of structure.
+        */
+       struct tc_u_knode __rcu *ht[1];
 };
 
 struct tc_u_common {
index 6742200b13071b6e63c200767a77a653d2e10c06..fbb7ebfc58c6761f6afb58e62646908b10e2bf09 100644 (file)
@@ -228,6 +228,7 @@ static int tcf_em_validate(struct tcf_proto *tp,
                                 * to replay the request.
                                 */
                                module_put(em->ops->owner);
+                               em->ops = NULL;
                                err = -EAGAIN;
                        }
 #endif
index bbedbfcb42c2505fceb57fa058f262d90e1670ed..245330ca0015c2fd2548ead861d379714151c901 100644 (file)
@@ -1702,6 +1702,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
 
        if (len > INT_MAX)
                len = INT_MAX;
+       if (unlikely(!access_ok(VERIFY_READ, buff, len)))
+               return -EFAULT;
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
@@ -1760,6 +1762,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
 
        if (size > INT_MAX)
                size = INT_MAX;
+       if (unlikely(!access_ok(VERIFY_WRITE, ubuf, size)))
+               return -EFAULT;
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
index abbb7dcd16897125863098cb48f6a6411488225c..59eeed43eda2d2651916dcc8698c12c7d7249e4e 100644 (file)
@@ -217,6 +217,8 @@ static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg)
 
        for (i = 0; i < arg->npages && arg->pages[i]; i++)
                __free_page(arg->pages[i]);
+
+       kfree(arg->pages);
 }
 
 static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
index 224a82f24d3c75e60c702bd89215b7934ded1ea8..1095be9c80ab809900d2bf0afbde9c63b6034a9d 100644 (file)
@@ -463,6 +463,8 @@ static int rsc_parse(struct cache_detail *cd,
                /* number of additional gid's */
                if (get_int(&mesg, &N))
                        goto out;
+               if (N < 0 || N > NGROUPS_MAX)
+                       goto out;
                status = -ENOMEM;
                rsci.cred.cr_group_info = groups_alloc(N);
                if (rsci.cred.cr_group_info == NULL)
index 33fb105d4352627319c604bdd03b7c9493f24adf..5199bb1a017e47b1b7503caf8075191dac1ade57 100644 (file)
@@ -921,7 +921,7 @@ static unsigned int cache_poll(struct file *filp, poll_table *wait,
        poll_wait(filp, &queue_wait, wait);
 
        /* alway allow write */
-       mask = POLL_OUT | POLLWRNORM;
+       mask = POLLOUT | POLLWRNORM;
 
        if (!rp)
                return mask;
index 612aa73bbc60c990a320054e4bd7d2846575428e..e6ce1517367f884608640b2532080ab6566b9379 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 e811f390f9f67ceb2e897ee8da79189417eacc75..82962f7e6e888f619ad79754f038732d5d5b6333 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 e37fbed879568da535aa540656e7b7ace508e2cb..ee5d3d253102bf5d81a39f953248a6a6ca7a38d6 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 e3015aede0d9443d99eba6b820aed104ab7515a6..9949722d99cebf6afa15953d8a9ac6a5c0bc2824 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 7e9acd9361c55bae557fcc51681585434b1755ef..91ffde82fa0c49eba3e11385aec9e334eb6b699a 100644 (file)
@@ -738,8 +738,9 @@ rpcrdma_reply_handler(struct rpcrdma_rep *rep)
        struct rpc_xprt *xprt = rep->rr_xprt;
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
        __be32 *iptr;
-       int credits, rdmalen, status;
+       int rdmalen, status;
        unsigned long cwnd;
+       u32 credits;
 
        /* Check status. If bad, signal disconnect and return rep to pool */
        if (rep->rr_len == ~0U) {
index d1b70397c60f0d8cb2ceb31c2feed19f7ca8f99a..0a16fb6f088590c142232ad99b2ac3b29304c169 100644 (file)
@@ -285,7 +285,7 @@ rpcr_to_rdmar(struct rpc_rqst *rqst)
  */
 struct rpcrdma_buffer {
        spinlock_t      rb_lock;        /* protects indexes */
-       int             rb_max_requests;/* client max requests */
+       u32             rb_max_requests;/* client max requests */
        struct list_head rb_mws;        /* optional memory windows/fmrs/frmrs */
        struct list_head rb_all;
        int             rb_send_index;
index 935205e6bcfe6da614fcc6c67e77754dc3a484fa..be1c9fa60b09dc713155c94e7bf6bcc6366fc7aa 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 a4cf364316de64a2a8df01350d31edf4af0866ea..14f09b3cb87c2fd9c87c67dfb67ce5e8df7d9f0f 100644 (file)
@@ -464,10 +464,11 @@ void tipc_link_reset(struct tipc_link *l_ptr)
        /* Clean up all queues, except inputq: */
        __skb_queue_purge(&l_ptr->outqueue);
        __skb_queue_purge(&l_ptr->deferred_queue);
-       skb_queue_splice_init(&l_ptr->wakeupq, &l_ptr->inputq);
-       if (!skb_queue_empty(&l_ptr->inputq))
+       if (!owner->inputq)
+               owner->inputq = &l_ptr->inputq;
+       skb_queue_splice_init(&l_ptr->wakeupq, owner->inputq);
+       if (!skb_queue_empty(owner->inputq))
                owner->action_flags |= TIPC_MSG_EVT;
-       owner->inputq = &l_ptr->inputq;
        l_ptr->next_out = NULL;
        l_ptr->unacked_window = 0;
        l_ptr->checkpoint = 1;
index f73e975af80b622c48d5ba92ec1e9504af4755e2..b4d4467d0bb051b09243c62aae2b3b2dca6d90a6 100644 (file)
@@ -2364,8 +2364,6 @@ int tipc_sk_rht_init(struct net *net)
                .hashfn = jhash,
                .max_shift = 20, /* 1M */
                .min_shift = 8,  /* 256 */
-               .grow_decision = rht_grow_above_75,
-               .shrink_decision = rht_shrink_below_30,
        };
 
        return rhashtable_init(&tn->sk_rht, &rht_params);
index 3af0ecf1cc16859abecb7451df5cabe35d6dbf08..2a0bbd22854bd97b377139200f9e6b5e0ec2662f 100644 (file)
@@ -1199,6 +1199,7 @@ out_fail_wq:
        regulatory_exit();
 out_fail_reg:
        debugfs_remove(ieee80211_debugfs_dir);
+       nl80211_exit();
 out_fail_nl80211:
        unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 out_fail_notifier:
index d78fd8b54515e630b67bf38d710b2b698f703c4c..b6f84f6a2a095ef0c94891f796ef6cf7cf9af65f 100644 (file)
@@ -2654,10 +2654,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
                                  &flags);
@@ -2666,6 +2662,10 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
            !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
                return -EOPNOTSUPP;
 
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
        wdev = rdev_add_virtual_intf(rdev,
                                nla_data(info->attrs[NL80211_ATTR_IFNAME]),
                                type, err ? NULL : &flags, &params);
@@ -4400,6 +4400,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
+       /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
+        * as userspace might just pass through the capabilities from the IEs
+        * directly, rather than enforcing this restriction and returning an
+        * error in this case.
+        */
+       if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
+               params.ht_capa = NULL;
+               params.vht_capa = NULL;
+       }
+
        /* When you run into this, adjust the code below for the new flag */
        BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
 
@@ -12528,9 +12538,7 @@ static int cfg80211_net_detect_results(struct sk_buff *msg,
                        }
 
                        for (j = 0; j < match->n_channels; j++) {
-                               if (nla_put_u32(msg,
-                                               NL80211_ATTR_WIPHY_FREQ,
-                                               match->channels[j])) {
+                               if (nla_put_u32(msg, j, match->channels[j])) {
                                        nla_nest_cancel(msg, nl_freqs);
                                        nla_nest_cancel(msg, nl_match);
                                        goto out;
index b586d0dcb09ebc9382fa0bd22016264e5bdd21c2..48dfc7b4e98130e4d8d5b265fceadd9004ed4f5e 100644 (file)
@@ -228,7 +228,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
 
 /* We keep a static world regulatory domain in case of the absence of CRDA */
 static const struct ieee80211_regdomain world_regdom = {
-       .n_reg_rules = 6,
+       .n_reg_rules = 8,
        .alpha2 =  "00",
        .reg_rules = {
                /* IEEE 802.11b/g, channels 1..11 */
index cee479bc655c4f317edb4e90cbcb06ec3b424b81..638af0655aaf8ec600ae5f6b201e252ca229d89d 100644 (file)
@@ -2269,11 +2269,9 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
                 * have the xfrm_state's. We need to wait for KM to
                 * negotiate new SA's or bail out with error.*/
                if (net->xfrm.sysctl_larval_drop) {
-                       dst_release(dst);
-                       xfrm_pols_put(pols, drop_pols);
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-
-                       return ERR_PTR(-EREMOTE);
+                       err = -EREMOTE;
+                       goto error;
                }
 
                err = -EAGAIN;
@@ -2324,7 +2322,8 @@ nopol:
 error:
        dst_release(dst);
 dropdst:
-       dst_release(dst_orig);
+       if (!(flags & XFRM_LOOKUP_KEEP_DST_REF))
+               dst_release(dst_orig);
        xfrm_pols_put(pols, drop_pols);
        return ERR_PTR(err);
 }
@@ -2338,7 +2337,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
                                    struct sock *sk, int flags)
 {
        struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
-                                           flags | XFRM_LOOKUP_QUEUE);
+                                           flags | XFRM_LOOKUP_QUEUE |
+                                           XFRM_LOOKUP_KEEP_DST_REF);
 
        if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
                return make_blackhole(net, dst_orig->ops->family, dst_orig);
diff --git a/scripts/gdb/linux/__init__.py b/scripts/gdb/linux/__init__.py
new file mode 100644 (file)
index 0000000..4680fb1
--- /dev/null
@@ -0,0 +1 @@
+# nothing to do for the initialization of this package
index 1684bcc78b34e42395b1db335c9122c405987c23..5fde34326dcf28312ab4c36cb09623ecb811760b 100644 (file)
@@ -152,7 +152,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
                goto out;
 
        /* No partial writes. */
-       length = EINVAL;
+       length = -EINVAL;
        if (*ppos != 0)
                goto out;
 
index 35324a8e83c867f126256f67b493b5320b9652c7..eeb691d1911f5716bb09b8eecacd24215a31564f 100644 (file)
@@ -1170,6 +1170,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
 
        if (info->count < 1)
                return -EINVAL;
+       if (!*info->id.name)
+               return -EINVAL;
+       if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name))
+               return -EINVAL;
        access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
                (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
                                 SNDRV_CTL_ELEM_ACCESS_INACTIVE|
index b03a638b420c18243776c45fda5884b422392c46..279e24f613051fddb8ca16375ab9031e6a703b03 100644 (file)
@@ -1552,6 +1552,8 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
                        if (! snd_pcm_playback_empty(substream)) {
                                snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);
                                snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING);
+                       } else {
+                               runtime->status->state = SNDRV_PCM_STATE_SETUP;
                        }
                        break;
                case SNDRV_PCM_STATE_RUNNING:
index f62780ed64adcc85465447838ee3b5d794690937..7821b07415a785c70982e03803ac34601770e3a9 100644 (file)
@@ -105,6 +105,8 @@ static void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum,
                int pitchbend = chan->midi_pitchbend;
                int segment;
 
+               if (pitchbend < -0x2000)
+                       pitchbend = -0x2000;
                if (pitchbend > 0x1FFF)
                        pitchbend = 0x1FFF;
 
index 0d580186ef1ac379bcd2cb699ac2f33baeac9029..5cc356db5351d903a7199b233fdfffc2bd8a674e 100644 (file)
@@ -33,7 +33,7 @@
  */
 #define MAX_MIDI_RX_BLOCKS     8
 
-#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 Ã‚µs */
+#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 microseconds */
 
 /* isochronous header parameters */
 #define ISO_DATA_LENGTH_SHIFT  16
@@ -78,7 +78,7 @@ static void pcm_period_tasklet(unsigned long data);
 int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
                      enum amdtp_stream_direction dir, enum cip_flags flags)
 {
-       s->unit = fw_unit_get(unit);
+       s->unit = unit;
        s->direction = dir;
        s->flags = flags;
        s->context = ERR_PTR(-1);
@@ -102,7 +102,6 @@ void amdtp_stream_destroy(struct amdtp_stream *s)
 {
        WARN_ON(amdtp_stream_running(s));
        mutex_destroy(&s->mutex);
-       fw_unit_put(s->unit);
 }
 EXPORT_SYMBOL(amdtp_stream_destroy);
 
index fc19c99654aa0284d400e58c51abc1a0c35495ee..611b7dae7ee54c932394c713022fd4501c84f7ca 100644 (file)
@@ -116,11 +116,22 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void
 bebob_card_free(struct snd_card *card)
 {
        struct snd_bebob *bebob = card->private_data;
 
+       snd_bebob_stream_destroy_duplex(bebob);
+       fw_unit_put(bebob->unit);
+
+       kfree(bebob->maudio_special_quirk);
+
        if (bebob->card_index >= 0) {
                mutex_lock(&devices_mutex);
                clear_bit(bebob->card_index, devices_used);
@@ -205,7 +216,7 @@ bebob_probe(struct fw_unit *unit,
        card->private_free = bebob_card_free;
 
        bebob->card = card;
-       bebob->unit = unit;
+       bebob->unit = fw_unit_get(unit);
        bebob->spec = spec;
        mutex_init(&bebob->mutex);
        spin_lock_init(&bebob->lock);
@@ -306,10 +317,11 @@ static void bebob_remove(struct fw_unit *unit)
        if (bebob == NULL)
                return;
 
-       kfree(bebob->maudio_special_quirk);
+       /* Awake bus-reset waiters. */
+       if (!completion_done(&bebob->bus_reset))
+               complete_all(&bebob->bus_reset);
 
-       snd_bebob_stream_destroy_duplex(bebob);
-       snd_card_disconnect(bebob->card);
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(bebob->card);
 }
 
index 0ebcabfdc7ce0162c9a77ed30ca038e6588cae63..98e4fc8121a1f4bdad82d892d79fa5c8241086af 100644 (file)
@@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob)
 static void
 destroy_both_connections(struct snd_bebob *bebob)
 {
-       break_both_connections(bebob);
-
        cmp_connection_destroy(&bebob->in_conn);
        cmp_connection_destroy(&bebob->out_conn);
 }
@@ -712,22 +710,16 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob)
        mutex_unlock(&bebob->mutex);
 }
 
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
 void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
 {
-       mutex_lock(&bebob->mutex);
-
-       amdtp_stream_pcm_abort(&bebob->rx_stream);
-       amdtp_stream_pcm_abort(&bebob->tx_stream);
-
-       amdtp_stream_stop(&bebob->rx_stream);
-       amdtp_stream_stop(&bebob->tx_stream);
-
        amdtp_stream_destroy(&bebob->rx_stream);
        amdtp_stream_destroy(&bebob->tx_stream);
 
        destroy_both_connections(bebob);
-
-       mutex_unlock(&bebob->mutex);
 }
 
 /*
index fa9cf761b610ad81e537634590f6f33cff7e674e..07dbd01d7a6bd336d901fa78b83365b44307b1a0 100644 (file)
@@ -311,14 +311,21 @@ end:
        return err;
 }
 
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
 static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 {
-       amdtp_stream_destroy(stream);
+       struct fw_iso_resources *resources;
 
        if (stream == &dice->tx_stream)
-               fw_iso_resources_destroy(&dice->tx_resources);
+               resources = &dice->tx_resources;
        else
-               fw_iso_resources_destroy(&dice->rx_resources);
+               resources = &dice->rx_resources;
+
+       amdtp_stream_destroy(stream);
+       fw_iso_resources_destroy(resources);
 }
 
 int snd_dice_stream_init_duplex(struct snd_dice *dice)
@@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice)
                goto end;
 
        err = init_stream(dice, &dice->rx_stream);
+       if (err < 0)
+               destroy_stream(dice, &dice->tx_stream);
 end:
        return err;
 }
@@ -340,10 +349,7 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 {
        snd_dice_transaction_clear_enable(dice);
 
-       stop_stream(dice, &dice->tx_stream);
        destroy_stream(dice, &dice->tx_stream);
-
-       stop_stream(dice, &dice->rx_stream);
        destroy_stream(dice, &dice->rx_stream);
 
        dice->substreams_counter = 0;
index 90d8f40ff72712f2ac67dc8f978855d59fd5f8d6..70a111d7f428af4a0487f80cf350767935c8cac0 100644 (file)
@@ -226,11 +226,20 @@ static void dice_card_strings(struct snd_dice *dice)
        strcpy(card->mixername, "DICE");
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void dice_card_free(struct snd_card *card)
 {
        struct snd_dice *dice = card->private_data;
 
+       snd_dice_stream_destroy_duplex(dice);
        snd_dice_transaction_destroy(dice);
+       fw_unit_put(dice->unit);
+
        mutex_destroy(&dice->mutex);
 }
 
@@ -251,7 +260,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 
        dice = card->private_data;
        dice->card = card;
-       dice->unit = unit;
+       dice->unit = fw_unit_get(unit);
        card->private_free = dice_card_free;
 
        spin_lock_init(&dice->lock);
@@ -305,10 +314,7 @@ static void dice_remove(struct fw_unit *unit)
 {
        struct snd_dice *dice = dev_get_drvdata(&unit->device);
 
-       snd_card_disconnect(dice->card);
-
-       snd_dice_stream_destroy_duplex(dice);
-
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(dice->card);
 }
 
index 3e2ed8e82cbc49b4699c82ad30776ef8a4300253..2682e7e3e5c98511e8bd26fddf452427f1e83a6a 100644 (file)
@@ -173,11 +173,23 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void
 efw_card_free(struct snd_card *card)
 {
        struct snd_efw *efw = card->private_data;
 
+       snd_efw_stream_destroy_duplex(efw);
+       snd_efw_transaction_remove_instance(efw);
+       fw_unit_put(efw->unit);
+
+       kfree(efw->resp_buf);
+
        if (efw->card_index >= 0) {
                mutex_lock(&devices_mutex);
                clear_bit(efw->card_index, devices_used);
@@ -185,7 +197,6 @@ efw_card_free(struct snd_card *card)
        }
 
        mutex_destroy(&efw->mutex);
-       kfree(efw->resp_buf);
 }
 
 static int
@@ -218,7 +229,7 @@ efw_probe(struct fw_unit *unit,
        card->private_free = efw_card_free;
 
        efw->card = card;
-       efw->unit = unit;
+       efw->unit = fw_unit_get(unit);
        mutex_init(&efw->mutex);
        spin_lock_init(&efw->lock);
        init_waitqueue_head(&efw->hwdep_wait);
@@ -289,10 +300,7 @@ static void efw_remove(struct fw_unit *unit)
 {
        struct snd_efw *efw = dev_get_drvdata(&unit->device);
 
-       snd_efw_stream_destroy_duplex(efw);
-       snd_efw_transaction_remove_instance(efw);
-
-       snd_card_disconnect(efw->card);
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(efw->card);
 }
 
index 4f440e16366780f097d8c03daeb45e01fb5e7eb0..c55db1bddc80a0ceab4997279643f73840943cef 100644 (file)
@@ -100,17 +100,22 @@ end:
        return err;
 }
 
+/*
+ * This function should be called before starting the stream or after stopping
+ * the streams.
+ */
 static void
 destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
 {
-       stop_stream(efw, stream);
-
-       amdtp_stream_destroy(stream);
+       struct cmp_connection *conn;
 
        if (stream == &efw->tx_stream)
-               cmp_connection_destroy(&efw->out_conn);
+               conn = &efw->out_conn;
        else
-               cmp_connection_destroy(&efw->in_conn);
+               conn = &efw->in_conn;
+
+       amdtp_stream_destroy(stream);
+       cmp_connection_destroy(&efw->out_conn);
 }
 
 static int
@@ -319,12 +324,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw)
 
 void snd_efw_stream_destroy_duplex(struct snd_efw *efw)
 {
-       mutex_lock(&efw->mutex);
-
        destroy_stream(efw, &efw->rx_stream);
        destroy_stream(efw, &efw->tx_stream);
-
-       mutex_unlock(&efw->mutex);
 }
 
 void snd_efw_stream_lock_changed(struct snd_efw *efw)
index 5f17b77ee15222ad0e43c3c6b5b13688b386417f..f0e4d502d60482ae8374cf9f830b739eb9e38753 100644 (file)
@@ -26,7 +26,7 @@
 int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
 {
        r->channels_mask = ~0uLL;
-       r->unit = fw_unit_get(unit);
+       r->unit = unit;
        mutex_init(&r->mutex);
        r->allocated = false;
 
@@ -42,7 +42,6 @@ void fw_iso_resources_destroy(struct fw_iso_resources *r)
 {
        WARN_ON(r->allocated);
        mutex_destroy(&r->mutex);
-       fw_unit_put(r->unit);
 }
 EXPORT_SYMBOL(fw_iso_resources_destroy);
 
index bda845afb470703ff0c05bd69f1caac5bfeabbd6..e6757cd8572422813b1627f3c5718ec4c53f2aac 100644 (file)
@@ -171,9 +171,10 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
        }
 
        /* Wait first packet */
-       err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT);
-       if (err < 0)
+       if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
                stop_stream(oxfw, stream);
+               err = -ETIMEDOUT;
+       }
 end:
        return err;
 }
@@ -337,6 +338,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
        stop_stream(oxfw, stream);
 }
 
+/*
+ * This function should be called before starting the stream or after stopping
+ * the streams.
+ */
 void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
                                     struct amdtp_stream *stream)
 {
@@ -347,8 +352,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
        else
                conn = &oxfw->in_conn;
 
-       stop_stream(oxfw, stream);
-
        amdtp_stream_destroy(stream);
        cmp_connection_destroy(conn);
 }
index 60e5cad0531aeb181d4cc6558f44b4cd6896f070..8c6ce019f437c310043a3686b634def68c92e424 100644 (file)
@@ -104,11 +104,23 @@ end:
        return err;
 }
 
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
 static void oxfw_card_free(struct snd_card *card)
 {
        struct snd_oxfw *oxfw = card->private_data;
        unsigned int i;
 
+       snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
+       if (oxfw->has_output)
+               snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+
+       fw_unit_put(oxfw->unit);
+
        for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
                kfree(oxfw->tx_stream_formats[i]);
                kfree(oxfw->rx_stream_formats[i]);
@@ -136,7 +148,7 @@ static int oxfw_probe(struct fw_unit *unit,
        oxfw = card->private_data;
        oxfw->card = card;
        mutex_init(&oxfw->mutex);
-       oxfw->unit = unit;
+       oxfw->unit = fw_unit_get(unit);
        oxfw->device_info = (const struct device_info *)id->driver_data;
        spin_lock_init(&oxfw->lock);
        init_waitqueue_head(&oxfw->hwdep_wait);
@@ -212,12 +224,7 @@ static void oxfw_remove(struct fw_unit *unit)
 {
        struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
 
-       snd_card_disconnect(oxfw->card);
-
-       snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
-       if (oxfw->has_output)
-               snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
-
+       /* No need to wait for releasing card object in this context. */
        snd_card_free_when_closed(oxfw->card);
 }
 
index 17e49a071af4497e5f39e0341cdee1db229cbc59..b408540798c1648d04a4ec1c36086844326affe1 100644 (file)
@@ -306,11 +306,12 @@ int snd_msndmix_new(struct snd_card *card)
        spin_lock_init(&chip->mixer_lock);
        strcpy(card->mixername, "MSND Pinnacle Mixer");
 
-       for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
+       for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) {
                err = snd_ctl_add(card,
                                  snd_ctl_new1(snd_msnd_controls + idx, chip));
                if (err < 0)
                        return err;
+       }
 
        return 0;
 }
index dfcb5e929f9fc9643701eb33f04aa8efd7f101d3..17c2637d842c1c366275683f30d2a3cb743560b6 100644 (file)
@@ -961,7 +961,6 @@ static int azx_alloc_cmd_io(struct azx *chip)
                dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
        return err;
 }
-EXPORT_SYMBOL_GPL(azx_alloc_cmd_io);
 
 static void azx_init_cmd_io(struct azx *chip)
 {
@@ -1026,7 +1025,6 @@ static void azx_init_cmd_io(struct azx *chip)
        azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
        spin_unlock_irq(&chip->reg_lock);
 }
-EXPORT_SYMBOL_GPL(azx_init_cmd_io);
 
 static void azx_free_cmd_io(struct azx *chip)
 {
@@ -1036,7 +1034,6 @@ static void azx_free_cmd_io(struct azx *chip)
        azx_writeb(chip, CORBCTL, 0);
        spin_unlock_irq(&chip->reg_lock);
 }
-EXPORT_SYMBOL_GPL(azx_free_cmd_io);
 
 static unsigned int azx_command_addr(u32 cmd)
 {
@@ -1167,7 +1164,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                }
        }
 
-       if (!bus->no_response_fallback)
+       if (bus->no_response_fallback)
                return -1;
 
        if (!chip->polling_mode && chip->poll_count < 2) {
@@ -1316,7 +1313,6 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
        else
                return azx_corb_send_cmd(bus, val);
 }
-EXPORT_SYMBOL_GPL(azx_send_cmd);
 
 /* get a response */
 static unsigned int azx_get_response(struct hda_bus *bus,
@@ -1330,7 +1326,6 @@ static unsigned int azx_get_response(struct hda_bus *bus,
        else
                return azx_rirb_get_response(bus, addr);
 }
-EXPORT_SYMBOL_GPL(azx_get_response);
 
 #ifdef CONFIG_SND_HDA_DSP_LOADER
 /*
index b680b4ec63313c8b1152390dbbf602018a212952..8ec5289f8e058538892aa04c402a4db9967c94c7 100644 (file)
@@ -687,12 +687,45 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
        return val;
 }
 
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+       unsigned int wcaps = get_wcaps(codec, nid);
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+       if (snd_hda_get_num_conns(codec, nid) != 1)
+               return false;
+       if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
+}
+
 /* initialize the amp value (only at the first time) */
 static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
 {
        unsigned int caps = query_amp_caps(codec, nid, dir);
        int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
-       snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+
+       if (is_stereo_amps(codec, nid, dir))
+               snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+       else
+               snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
+}
+
+/* update the amp, doing in stereo or mono depending on NID */
+static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
+                     unsigned int mask, unsigned int val)
+{
+       if (is_stereo_amps(codec, nid, dir))
+               return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
+                                               mask, val);
+       else
+               return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+                                               mask, val);
 }
 
 /* calculate amp value mask we can modify;
@@ -732,7 +765,7 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
                return;
 
        val &= mask;
-       snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val);
+       update_amp(codec, nid, dir, idx, mask, val);
 }
 
 static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
@@ -4424,13 +4457,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
        has_amp = nid_has_mute(codec, mix, HDA_INPUT);
        for (i = 0; i < nums; i++) {
                if (has_amp)
-                       snd_hda_codec_amp_stereo(codec, mix,
-                                                HDA_INPUT, i,
-                                                0xff, HDA_AMP_MUTE);
+                       update_amp(codec, mix, HDA_INPUT, i,
+                                  0xff, HDA_AMP_MUTE);
                else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
-                       snd_hda_codec_amp_stereo(codec, conn[i],
-                                                HDA_OUTPUT, 0,
-                                                0xff, HDA_AMP_MUTE);
+                       update_amp(codec, conn[i], HDA_OUTPUT, 0,
+                                  0xff, HDA_AMP_MUTE);
        }
 }
 
index 36d2f20db7a4201b999155e759e3e22b6fe3f753..a8a1e14272a1e574302da56ad0ad7540bf8fd60d 100644 (file)
@@ -1966,7 +1966,7 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Panther Point */
        { PCI_DEVICE(0x8086, 0x1e20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Lynx Point */
        { PCI_DEVICE(0x8086, 0x8c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -1989,7 +1989,7 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
        /* Sunrise Point */
        { PCI_DEVICE(0x8086, 0xa170),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
index ce5a6da834199bd2acd7e6ee18fd123b4f078820..05e19f78b4cb8689ff8ac1b0b4f699bdbf5759da 100644 (file)
@@ -134,13 +134,38 @@ static void print_amp_caps(struct snd_info_buffer *buffer,
                    (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
 }
 
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int wcaps, int indices)
+{
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       /* check for a stereo-to-mono mix; it must be:
+        * only a single connection, only for input, and only a mixer widget
+        */
+       if (indices != 1 || dir != HDA_INPUT ||
+           get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+
+       if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       /* the connection source is a stereo? */
+       wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP);
+       return !!(wcaps & AC_WCAP_STEREO);
+}
+
 static void print_amp_vals(struct snd_info_buffer *buffer,
                           struct hda_codec *codec, hda_nid_t nid,
-                          int dir, int stereo, int indices)
+                          int dir, unsigned int wcaps, int indices)
 {
        unsigned int val;
+       bool stereo;
        int i;
 
+       stereo = is_stereo_amps(codec, nid, dir, wcaps, indices);
+
        dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
        for (i = 0; i < indices; i++) {
                snd_iprintf(buffer, " [");
@@ -757,12 +782,10 @@ static void print_codec_info(struct snd_info_entry *entry,
                            (codec->single_adc_amp &&
                             wid_type == AC_WID_AUD_IN))
                                print_amp_vals(buffer, codec, nid, HDA_INPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              1);
+                                              wid_caps, 1);
                        else
                                print_amp_vals(buffer, codec, nid, HDA_INPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              conn_len);
+                                              wid_caps, conn_len);
                }
                if (wid_caps & AC_WCAP_OUT_AMP) {
                        snd_iprintf(buffer, "  Amp-Out caps: ");
@@ -771,11 +794,10 @@ static void print_codec_info(struct snd_info_entry *entry,
                        if (wid_type == AC_WID_PIN &&
                            codec->pin_amp_workaround)
                                print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                              wid_caps & AC_WCAP_STEREO,
-                                              conn_len);
+                                              wid_caps, conn_len);
                        else
                                print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                              wid_caps & AC_WCAP_STEREO, 1);
+                                              wid_caps, 1);
                }
 
                switch (wid_type) {
index 1589c9bcce3e15a230f87d352f2ae165252c358d..dd2b3d92071f698f41a75d2d7b7877eb6b357c00 100644 (file)
@@ -393,6 +393,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
        SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
        SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
+       SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81),
        SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
        SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
        {} /* terminator */
@@ -584,6 +585,7 @@ static int patch_cs420x(struct hda_codec *codec)
                return -ENOMEM;
 
        spec->gen.automute_hook = cs_automute;
+       codec->single_adc_amp = 1;
 
        snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
                           cs420x_fixups);
index fd3ed18670e9c4005d115a26f6410c7efd4faff8..da67ea8645a6e8462f23b8f8b1e96044e66812f7 100644 (file)
@@ -223,6 +223,7 @@ enum {
        CXT_PINCFG_LENOVO_TP410,
        CXT_PINCFG_LEMOTE_A1004,
        CXT_PINCFG_LEMOTE_A1205,
+       CXT_PINCFG_COMPAQ_CQ60,
        CXT_FIXUP_STEREO_DMIC,
        CXT_FIXUP_INC_MIC_BOOST,
        CXT_FIXUP_HEADPHONE_MIC_PIN,
@@ -660,6 +661,15 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = cxt_pincfg_lemote,
        },
+       [CXT_PINCFG_COMPAQ_CQ60] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* 0x17 was falsely set up as a mic, it should 0x1d */
+                       { 0x17, 0x400001f0 },
+                       { 0x1d, 0x97a70120 },
+                       { }
+               }
+       },
        [CXT_FIXUP_STEREO_DMIC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt_fixup_stereo_dmic,
@@ -769,6 +779,7 @@ static const struct hda_model_fixup cxt5047_fixup_models[] = {
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
+       SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
        {}
 };
index b2b24a8b3dac8c49d2bb55c3142eecd967e73608..74382137b9f5abcd67b9c4c44581c9a80f26d17d 100644 (file)
@@ -396,7 +396,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
 {
        /* We currently only handle front, HP */
        static hda_nid_t pins[] = {
-               0x0f, 0x10, 0x14, 0x15, 0
+               0x0f, 0x10, 0x14, 0x15, 0x17, 0
        };
        hda_nid_t *p;
        for (p = pins; *p; p++)
@@ -5036,6 +5036,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
@@ -5209,6 +5210,13 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x17, 0x40000000},
                {0x1d, 0x40700001},
                {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
+               {0x12, 0x90a60170},
+               {0x14, 0x90170140},
+               {0x17, 0x40000000},
+               {0x1d, 0x40700001},
+               {0x21, 0x02211050}),
        SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
                {0x12, 0x90a60130},
                {0x13, 0x40000000},
index 6d36c5b7880504457430718a8f23f2dbc0e9a9ba..87eff3173ce924ae89596068b5bf8dcd38e7482e 100644 (file)
@@ -79,6 +79,7 @@ enum {
        STAC_ALIENWARE_M17X,
        STAC_92HD89XX_HP_FRONT_JACK,
        STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
+       STAC_92HD73XX_ASUS_MOBO,
        STAC_92HD73XX_MODELS
 };
 
@@ -1911,7 +1912,18 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
        [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs,
-       }
+       },
+       [STAC_92HD73XX_ASUS_MOBO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* enable 5.1 and SPDIF out */
+                       { 0x0c, 0x01014411 },
+                       { 0x0d, 0x01014410 },
+                       { 0x0e, 0x01014412 },
+                       { 0x22, 0x014b1180 },
+                       { }
+               }
+       },
 };
 
 static const struct hda_model_fixup stac92hd73xx_models[] = {
@@ -1923,6 +1935,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
        { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
        { .id = STAC_DELL_EQ, .name = "dell-eq" },
        { .id = STAC_ALIENWARE_M17X, .name = "alienware" },
+       { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
        {}
 };
 
@@ -1975,6 +1988,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
                                "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
                                "unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10",
+                     STAC_92HD73XX_ASUS_MOBO),
        {} /* terminator */
 };
 
index 1579e994acf881dfacb1aae23afb6095f32ff13f..e7d08806f3e92d9c98a7c5bfc4fe84d5aead3f5f 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 466a821da98ca958e2103c28b1e07f0130033422..b327e5cc8de352b84a8bffc5260e4d6e6ea5f2df 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 b8e7bad05eb14a9ef7e6393646f776c910c0f898..b6625c8c411b8a66a6d1cbaf807109f7ccc8ec71 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 a366b3503c282cad1cd2c857eafb384b8b8e56bb..da861b44413f7f7f6e199b9d2aa9340691ed5b2f 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 12ae814eff214fc2977fe9c0bdde17e5025e2cdb..6eaf081cad5083222e03bf54935ded0130bfec08 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 fb0b7e8b08ff4cd11a2656fe76fe10898aeded6b..841d05946b888fc5b905445f61611f44df685ff6 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 b1f08d51149526006021c7314aa4f3e15847de3d..80b153857a88ac25e86d3c4df1fc6ad45f108dc7 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 f5ad214663f98b4dbbdc3c2a4180d6142d09688c..8de836165cf2ed1978c4846ac56e84bcbae4e6d1 100644 (file)
@@ -46,8 +46,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include <asm/mach-types.h>
-
 #include "../codecs/wm8731.h"
 #include "atmel-pcm.h"
 #include "atmel_ssc_dai.h"
@@ -171,9 +169,7 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
        int ret;
 
        if (!np) {
-               if (!(machine_is_at91sam9g20ek() ||
-                       machine_is_at91sam9g20ek_2mmc()))
-                       return -ENODEV;
+               return -ENODEV;
        }
 
        ret = atmel_ssc_set_audio(0);
@@ -210,39 +206,37 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
        card->dev = &pdev->dev;
 
        /* Parse device node info */
-       if (np) {
-               ret = snd_soc_of_parse_card_name(card, "atmel,model");
-               if (ret)
-                       goto err;
-
-               ret = snd_soc_of_parse_audio_routing(card,
-                       "atmel,audio-routing");
-               if (ret)
-                       goto err;
-
-               /* Parse codec info */
-               at91sam9g20ek_dai.codec_name = NULL;
-               codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
-               if (!codec_np) {
-                       dev_err(&pdev->dev, "codec info missing\n");
-                       return -EINVAL;
-               }
-               at91sam9g20ek_dai.codec_of_node = codec_np;
-
-               /* Parse dai and platform info */
-               at91sam9g20ek_dai.cpu_dai_name = NULL;
-               at91sam9g20ek_dai.platform_name = NULL;
-               cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
-               if (!cpu_np) {
-                       dev_err(&pdev->dev, "dai and pcm info missing\n");
-                       return -EINVAL;
-               }
-               at91sam9g20ek_dai.cpu_of_node = cpu_np;
-               at91sam9g20ek_dai.platform_of_node = cpu_np;
-
-               of_node_put(codec_np);
-               of_node_put(cpu_np);
+       ret = snd_soc_of_parse_card_name(card, "atmel,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card,
+               "atmel,audio-routing");
+       if (ret)
+               goto err;
+
+       /* Parse codec info */
+       at91sam9g20ek_dai.codec_name = NULL;
+       codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+       if (!codec_np) {
+               dev_err(&pdev->dev, "codec info missing\n");
+               return -EINVAL;
+       }
+       at91sam9g20ek_dai.codec_of_node = codec_np;
+
+       /* Parse dai and platform info */
+       at91sam9g20ek_dai.cpu_dai_name = NULL;
+       at91sam9g20ek_dai.platform_name = NULL;
+       cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "dai and pcm info missing\n");
+               return -EINVAL;
        }
+       at91sam9g20ek_dai.cpu_of_node = cpu_np;
+       at91sam9g20ek_dai.platform_of_node = cpu_np;
+
+       of_node_put(codec_np);
+       of_node_put(cpu_np);
 
        ret = snd_soc_register_card(card);
        if (ret) {
index 7b7fbcd49e5e424c25e47d9e6a1aee77065358d5..c7cd60f009e93e69ef2220eec3eb6ec97a9e6500 100644 (file)
@@ -16,7 +16,7 @@ config SND_EP93XX_SOC_AC97
 
 config SND_EP93XX_SOC_SNAPPERCL15
         tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
-        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
+        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C
         select SND_EP93XX_SOC_I2S
         select SND_SOC_TLV320AIC23_I2C
         help
index 064e6c18e10923fd75609b750405dbc33f9db6af..061c46587628b5284a38b51d39a777f6341c2c1a 100644 (file)
@@ -69,7 +69,8 @@ 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_MAX98925 if I2C
        select SND_SOC_MAX9850 if I2C
        select SND_SOC_MAX9768 if I2C
        select SND_SOC_MAX9877 if I2C
@@ -141,7 +142,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
@@ -460,6 +462,9 @@ config SND_SOC_MAX98095
 config SND_SOC_MAX98357A
        tristate
 
+config SND_SOC_MAX98925
+       tristate
+
 config SND_SOC_MAX9850
        tristate
 
@@ -744,8 +749,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 69b8666d187a0e8d1e2a532e68e2509acc95da7e..abe2d7edf65c7af29dbad5de78b2c0fe2beeef16 100644 (file)
@@ -65,6 +65,7 @@ snd-soc-max98088-objs := max98088.o
 snd-soc-max98090-objs := max98090.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max98357a-objs := max98357a.o
+snd-soc-max98925-objs := max98925.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
@@ -145,6 +146,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
@@ -247,6 +250,7 @@ obj-$(CONFIG_SND_SOC_MAX98088)      += snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
 obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX98357A)        += snd-soc-max98357a.o
+obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
@@ -323,6 +327,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 7895689588daa8db7ab023361b9e4c65bf9851c2..88ca9cb0ce79374f9e9e02d0530ff689efdbbefe 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 70ab35744abadd9970a65a86eaee155f70244db1..7ad8e156e2df9010a6d2fbe2d70bf45358da79af 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 b67480f1b1aa4a7dcfb6c03b10b2ecd826875989..4373ada95648e6890f013582b97c355b45e76dd1 100644 (file)
@@ -317,7 +317,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-       unsigned int deemph = ucontrol->value.enumerated.item[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
@@ -333,7 +333,7 @@ static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = adav80x->deemph;
+       ucontrol->value.integer.value[0] = adav80x->deemph;
        return 0;
 };
 
index 16ce9f9fefa175458bdf7a9ad49041b7faa821fc..298dedc051403b9dd8ae309a134e6fb9447893c2 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 70861c7b1631ab577acf506f8af18f2386a0852a..81b54a270bd8f800637108d027f9edfffb464d04 100644 (file)
@@ -76,7 +76,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
@@ -92,7 +92,7 @@ static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = ak4641->deemph;
+       ucontrol->value.integer.value[0] = ak4641->deemph;
        return 0;
 };
 
index dde8b49c19add3ded9d806b52bcc7986b95b0ae2..13585e88f59704530e17ff36c0394b17d8c04571 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 632e89f793a78d2691dfb2e33b3516f0f483aeee..2a58b1dccd2f18cb41221c45ac4d026e731240c9 100644 (file)
@@ -343,25 +343,25 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route ak4671_intercon[] = {
-       {"DAC Left", "NULL", "PMPLL"},
-       {"DAC Right", "NULL", "PMPLL"},
-       {"ADC Left", "NULL", "PMPLL"},
-       {"ADC Right", "NULL", "PMPLL"},
+       {"DAC Left", NULL, "PMPLL"},
+       {"DAC Right", NULL, "PMPLL"},
+       {"ADC Left", NULL, "PMPLL"},
+       {"ADC Right", NULL, "PMPLL"},
 
        /* Outputs */
-       {"LOUT1", "NULL", "LOUT1 Mixer"},
-       {"ROUT1", "NULL", "ROUT1 Mixer"},
-       {"LOUT2", "NULL", "LOUT2 Mix Amp"},
-       {"ROUT2", "NULL", "ROUT2 Mix Amp"},
-       {"LOUT3", "NULL", "LOUT3 Mixer"},
-       {"ROUT3", "NULL", "ROUT3 Mixer"},
+       {"LOUT1", NULL, "LOUT1 Mixer"},
+       {"ROUT1", NULL, "ROUT1 Mixer"},
+       {"LOUT2", NULL, "LOUT2 Mix Amp"},
+       {"ROUT2", NULL, "ROUT2 Mix Amp"},
+       {"LOUT3", NULL, "LOUT3 Mixer"},
+       {"ROUT3", NULL, "ROUT3 Mixer"},
 
        {"LOUT1 Mixer", "DACL", "DAC Left"},
        {"ROUT1 Mixer", "DACR", "DAC Right"},
        {"LOUT2 Mixer", "DACHL", "DAC Left"},
        {"ROUT2 Mixer", "DACHR", "DAC Right"},
-       {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"},
-       {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"},
+       {"LOUT2 Mix Amp", NULL, "LOUT2 Mixer"},
+       {"ROUT2 Mix Amp", NULL, "ROUT2 Mixer"},
        {"LOUT3 Mixer", "DACSL", "DAC Left"},
        {"ROUT3 Mixer", "DACSR", "DAC Right"},
 
@@ -381,18 +381,18 @@ static const struct snd_soc_dapm_route ak4671_intercon[] = {
        {"LIN2", NULL, "Mic Bias"},
        {"RIN2", NULL, "Mic Bias"},
 
-       {"ADC Left", "NULL", "LIN MUX"},
-       {"ADC Right", "NULL", "RIN MUX"},
+       {"ADC Left", NULL, "LIN MUX"},
+       {"ADC Right", NULL, "RIN MUX"},
 
        /* Analog Loops */
-       {"LIN1 Mixing Circuit", "NULL", "LIN1"},
-       {"RIN1 Mixing Circuit", "NULL", "RIN1"},
-       {"LIN2 Mixing Circuit", "NULL", "LIN2"},
-       {"RIN2 Mixing Circuit", "NULL", "RIN2"},
-       {"LIN3 Mixing Circuit", "NULL", "LIN3"},
-       {"RIN3 Mixing Circuit", "NULL", "RIN3"},
-       {"LIN4 Mixing Circuit", "NULL", "LIN4"},
-       {"RIN4 Mixing Circuit", "NULL", "RIN4"},
+       {"LIN1 Mixing Circuit", NULL, "LIN1"},
+       {"RIN1 Mixing Circuit", NULL, "RIN1"},
+       {"LIN2 Mixing Circuit", NULL, "LIN2"},
+       {"RIN2 Mixing Circuit", NULL, "RIN2"},
+       {"LIN3 Mixing Circuit", NULL, "LIN3"},
+       {"RIN3 Mixing Circuit", NULL, "RIN3"},
+       {"LIN4 Mixing Circuit", NULL, "LIN4"},
+       {"RIN4 Mixing Circuit", NULL, "RIN4"},
 
        {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"},
        {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"},
index 29202610dd0dd90d72329265633844a3d833d640..9015b44a9e1101d47d25ad94934de6420ca8d1a6 100644 (file)
@@ -1901,7 +1901,7 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll)
 static int arizona_enable_fll(struct arizona_fll *fll)
 {
        struct arizona *arizona = fll->arizona;
-       int ret;
+       unsigned long time_left;
        bool use_sync = false;
        int already_enabled = arizona_is_enabled_fll(fll);
        struct arizona_fll_cfg cfg;
@@ -1977,9 +1977,9 @@ static int arizona_enable_fll(struct arizona_fll *fll)
                regmap_update_bits_async(arizona->regmap, fll->base + 1,
                                         ARIZONA_FLL1_FREERUN, 0);
 
-       ret = wait_for_completion_timeout(&fll->ok,
+       time_left = wait_for_completion_timeout(&fll->ok,
                                          msecs_to_jiffies(250));
-       if (ret == 0)
+       if (time_left == 0)
                arizona_fll_warn(fll, "Timed out waiting for lock\n");
 
        return 0;
index f2b8aad21274aec951fdabc20887b970ef2e1aaa..60598b23034111cb8646b7a8607bca95db79cf01 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 ce6086835ebdbea24df543cf0f7c271d3bf64a1b..cac48ddf3ba6bb71a20da39945fd6f819b24037a 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 79a4efcb894c192c763c649083081e4c75fbece3..e770ee6f36da1eab0c0952a2f968f3b780db6755 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 0b10979513c4a93dba590a09be02d20a0f4cb35e..0f334bc1b63c78893a452cd5d2cbda86b2f47a0f 100644 (file)
@@ -420,7 +420,7 @@ static int cx20442_platform_probe(struct platform_device *pdev)
                        &cx20442_codec_dev, &cx20442_dai, 1);
 }
 
-static int __exit cx20442_platform_remove(struct platform_device *pdev)
+static int cx20442_platform_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
        return 0;
@@ -431,7 +431,7 @@ static struct platform_driver cx20442_platform_driver = {
                .name = "cx20442-codec",
                },
        .probe = cx20442_platform_probe,
-       .remove = __exit_p(cx20442_platform_remove),
+       .remove = cx20442_platform_remove,
 };
 
 module_platform_driver(cx20442_platform_driver);
index ffe96175a8a5ac62ee4721c1f17a54c305d447c7..911c26c705fc8d226e819d469c669b72f989517a 100644 (file)
@@ -876,11 +876,11 @@ static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = {
 
 static const struct snd_soc_dapm_route da732x_dapm_routes[] = {
        /* Inputs */
-       {"AUX1L PGA", "NULL", "AUX1L"},
-       {"AUX1R PGA", "NULL", "AUX1R"},
+       {"AUX1L PGA", NULL, "AUX1L"},
+       {"AUX1R PGA", NULL, "AUX1R"},
        {"MIC1 PGA", NULL, "MIC1"},
-       {"MIC2 PGA", "NULL", "MIC2"},
-       {"MIC3 PGA", "NULL", "MIC3"},
+       {"MIC2 PGA", NULL, "MIC2"},
+       {"MIC3 PGA", NULL, "MIC3"},
 
        /* Capture Path */
        {"ADC1 Left MUX", "MIC1", "MIC1 PGA"},
index f27325155acef31e1f4a7fff4ea970b9405ca8a7..c5f35a07e8e48106335df49153acd81e104f7aa9 100644 (file)
@@ -120,7 +120,7 @@ static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = es8328->deemph;
+       ucontrol->value.integer.value[0] = es8328->deemph;
        return 0;
 }
 
@@ -129,7 +129,7 @@ static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret;
 
        if (deemph > 1)
index 1806333ea29e5a6b49e2a0adb8c58257d34b7508..bf3e933ee895752352e90f610195f39fc6cc058f 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);
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
new file mode 100644 (file)
index 0000000..9b5a17d
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * max98925.c -- ALSA SoC Stereo MAX98925 driver
+ * Copyright 2013-15 Maxim Integrated Products
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98925.h"
+
+static const char *const dai_text[] = {
+       "Left", "Right", "LeftRight", "LeftRightDiv2",
+};
+
+static const char * const max98925_boost_voltage_text[] = {
+       "8.5V", "8.25V", "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V",
+       "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98925_boost_voltage,
+       MAX98925_CONFIGURATION, M98925_BST_VOUT_SHIFT,
+       max98925_boost_voltage_text);
+
+static const char *const hpf_text[] = {
+       "Disable", "DC Block", "100Hz", "200Hz", "400Hz", "800Hz",
+};
+
+static const struct reg_default max98925_reg[] = {
+       { 0x0B, 0x00 }, /* IRQ Enable0 */
+       { 0x0C, 0x00 }, /* IRQ Enable1 */
+       { 0x0D, 0x00 }, /* IRQ Enable2 */
+       { 0x0E, 0x00 }, /* IRQ Clear0 */
+       { 0x0F, 0x00 }, /* IRQ Clear1 */
+       { 0x10, 0x00 }, /* IRQ Clear2 */
+       { 0x11, 0xC0 }, /* Map0 */
+       { 0x12, 0x00 }, /* Map1 */
+       { 0x13, 0x00 }, /* Map2 */
+       { 0x14, 0xF0 }, /* Map3 */
+       { 0x15, 0x00 }, /* Map4 */
+       { 0x16, 0xAB }, /* Map5 */
+       { 0x17, 0x89 }, /* Map6 */
+       { 0x18, 0x00 }, /* Map7 */
+       { 0x19, 0x00 }, /* Map8 */
+       { 0x1A, 0x06 }, /* DAI Clock Mode 1 */
+       { 0x1B, 0xC0 }, /* DAI Clock Mode 2 */
+       { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */
+       { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */
+       { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */
+       { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */
+       { 0x20, 0x50 }, /* Format */
+       { 0x21, 0x00 }, /* TDM Slot Select */
+       { 0x22, 0x00 }, /* DOUT Configuration VMON */
+       { 0x23, 0x00 }, /* DOUT Configuration IMON */
+       { 0x24, 0x00 }, /* DOUT Configuration VBAT */
+       { 0x25, 0x00 }, /* DOUT Configuration VBST */
+       { 0x26, 0x00 }, /* DOUT Configuration FLAG */
+       { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */
+       { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */
+       { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */
+       { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */
+       { 0x2B, 0x02 }, /* DOUT Drive Strength */
+       { 0x2C, 0x90 }, /* Filters */
+       { 0x2D, 0x00 }, /* Gain */
+       { 0x2E, 0x02 }, /* Gain Ramping */
+       { 0x2F, 0x00 }, /* Speaker Amplifier */
+       { 0x30, 0x0A }, /* Threshold */
+       { 0x31, 0x00 }, /* ALC Attack */
+       { 0x32, 0x80 }, /* ALC Atten and Release */
+       { 0x33, 0x00 }, /* ALC Infinite Hold Release */
+       { 0x34, 0x92 }, /* ALC Configuration */
+       { 0x35, 0x01 }, /* Boost Converter */
+       { 0x36, 0x00 }, /* Block Enable */
+       { 0x37, 0x00 }, /* Configuration */
+       { 0x38, 0x00 }, /* Global Enable */
+       { 0x3A, 0x00 }, /* Boost Limiter */
+};
+
+static const struct soc_enum max98925_dai_enum =
+       SOC_ENUM_SINGLE(MAX98925_GAIN, 5, ARRAY_SIZE(dai_text), dai_text);
+
+static const struct soc_enum max98925_hpf_enum =
+       SOC_ENUM_SINGLE(MAX98925_FILTERS, 0, ARRAY_SIZE(hpf_text), hpf_text);
+
+static const struct snd_kcontrol_new max98925_hpf_sel_mux =
+       SOC_DAPM_ENUM("Rc Filter MUX Mux", max98925_hpf_enum);
+
+static const struct snd_kcontrol_new max98925_dai_sel_mux =
+       SOC_DAPM_ENUM("DAI IN MUX Mux", max98925_dai_enum);
+
+static int max98925_dac_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               regmap_update_bits(max98925->regmap,
+                       MAX98925_BLOCK_ENABLE,
+                       M98925_BST_EN_MASK |
+                       M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK,
+                       M98925_BST_EN_MASK |
+                       M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               regmap_update_bits(max98925->regmap,
+                       MAX98925_BLOCK_ENABLE, M98925_BST_EN_MASK |
+                       M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK, 0);
+               break;
+       default:
+               return 0;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget max98925_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_MUX("DAI IN MUX", SND_SOC_NOPM, 0, 0,
+                               &max98925_dai_sel_mux),
+       SND_SOC_DAPM_MUX("Rc Filter MUX", SND_SOC_NOPM, 0, 0,
+                               &max98925_hpf_sel_mux),
+       SND_SOC_DAPM_DAC_E("Amp Enable", NULL, MAX98925_BLOCK_ENABLE,
+                       M98925_SPK_EN_SHIFT, 0, max98925_dac_event,
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("Global Enable", MAX98925_GLOBAL_ENABLE,
+                       M98925_EN_SHIFT, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("BE_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98925_audio_map[] = {
+       {"DAI IN MUX", "Left", "DAI_OUT"},
+       {"DAI IN MUX", "Right", "DAI_OUT"},
+       {"DAI IN MUX", "LeftRight", "DAI_OUT"},
+       {"DAI IN MUX", "LeftRightDiv2", "DAI_OUT"},
+       {"Rc Filter MUX", "Disable", "DAI IN MUX"},
+       {"Rc Filter MUX", "DC Block", "DAI IN MUX"},
+       {"Rc Filter MUX", "100Hz", "DAI IN MUX"},
+       {"Rc Filter MUX", "200Hz", "DAI IN MUX"},
+       {"Rc Filter MUX", "400Hz", "DAI IN MUX"},
+       {"Rc Filter MUX", "800Hz", "DAI IN MUX"},
+       {"Amp Enable", NULL, "Rc Filter MUX"},
+       {"BE_OUT", NULL, "Amp Enable"},
+       {"BE_OUT", NULL, "Global Enable"},
+};
+
+static bool max98925_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MAX98925_VBAT_DATA:
+       case MAX98925_VBST_DATA:
+       case MAX98925_LIVE_STATUS0:
+       case MAX98925_LIVE_STATUS1:
+       case MAX98925_LIVE_STATUS2:
+       case MAX98925_STATE0:
+       case MAX98925_STATE1:
+       case MAX98925_STATE2:
+       case MAX98925_FLAG0:
+       case MAX98925_FLAG1:
+       case MAX98925_FLAG2:
+       case MAX98925_REV_VERSION:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool max98925_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MAX98925_IRQ_CLEAR0:
+       case MAX98925_IRQ_CLEAR1:
+       case MAX98925_IRQ_CLEAR2:
+       case MAX98925_ALC_HOLD_RLS:
+               return false;
+       default:
+               return true;
+       }
+}
+
+static DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0);
+
+static const struct snd_kcontrol_new max98925_snd_controls[] = {
+       SOC_SINGLE_TLV("Speaker Volume", MAX98925_GAIN,
+               M98925_SPK_GAIN_SHIFT, (1<<M98925_SPK_GAIN_WIDTH)-1, 0,
+               max98925_spk_tlv),
+       SOC_SINGLE("Ramp Switch", MAX98925_GAIN_RAMPING,
+                               M98925_SPK_RMP_EN_SHIFT, 1, 0),
+       SOC_SINGLE("ZCD Switch", MAX98925_GAIN_RAMPING,
+                               M98925_SPK_ZCD_EN_SHIFT, 1, 0),
+       SOC_SINGLE("ALC Switch", MAX98925_THRESHOLD,
+                               M98925_ALC_EN_SHIFT, 1, 0),
+       SOC_SINGLE("ALC Threshold", MAX98925_THRESHOLD, M98925_ALC_TH_SHIFT,
+                               (1<<M98925_ALC_TH_WIDTH)-1, 0),
+       SOC_ENUM("Boost Output Voltage", max98925_boost_voltage),
+};
+
+/* codec sample rate and n/m dividers parameter table */
+static const struct {
+       int rate;
+       int  sr;
+       int divisors[3][2];
+} rate_table[] = {
+       {
+               .rate = 8000,
+               .sr = 0,
+               .divisors = { {1, 375}, {5, 1764}, {1, 384} }
+       },
+       {
+               .rate = 11025,
+               .sr = 1,
+               .divisors = { {147, 40000}, {1, 256}, {147, 40960} }
+       },
+       {
+               .rate = 12000,
+               .sr = 2,
+               .divisors = { {1, 250}, {5, 1176}, {1, 256} }
+       },
+       {
+               .rate = 16000,
+               .sr = 3,
+               .divisors = { {2, 375}, {5, 882}, {1, 192} }
+       },
+       {
+               .rate = 22050,
+               .sr = 4,
+               .divisors = { {147, 20000}, {1, 128}, {147, 20480} }
+       },
+       {
+               .rate = 24000,
+               .sr = 5,
+               .divisors = { {1, 125}, {5, 588}, {1, 128} }
+       },
+       {
+               .rate = 32000,
+               .sr = 6,
+               .divisors = { {4, 375}, {5, 441}, {1, 96} }
+       },
+       {
+               .rate = 44100,
+               .sr = 7,
+               .divisors = { {147, 10000}, {1, 64}, {147, 10240} }
+       },
+       {
+               .rate = 48000,
+               .sr = 8,
+               .divisors = { {2, 125}, {5, 294}, {1, 64} }
+       },
+};
+
+static inline int max98925_rate_value(struct snd_soc_codec *codec,
+               int rate, int clock, int *value, int *n, int *m)
+{
+       int ret = -EINVAL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+               if (rate_table[i].rate >= rate) {
+                       *value = rate_table[i].sr;
+                       *n = rate_table[i].divisors[clock][0];
+                       *m = rate_table[i].divisors[clock][1];
+                       ret = 0;
+                       break;
+               }
+       }
+       dev_dbg(codec->dev, "%s: sample rate is %d, returning %d\n",
+                               __func__, rate_table[i].rate, *value);
+       return ret;
+}
+
+static void max98925_set_sense_data(struct max98925_priv *max98925)
+{
+       /* set VMON slots */
+       regmap_update_bits(max98925->regmap,
+               MAX98925_DOUT_CFG_VMON,
+               M98925_DAI_VMON_EN_MASK, M98925_DAI_VMON_EN_MASK);
+       regmap_update_bits(max98925->regmap,
+               MAX98925_DOUT_CFG_VMON,
+               M98925_DAI_VMON_SLOT_MASK,
+               max98925->v_slot << M98925_DAI_VMON_SLOT_SHIFT);
+       /* set IMON slots */
+       regmap_update_bits(max98925->regmap,
+               MAX98925_DOUT_CFG_IMON,
+               M98925_DAI_IMON_EN_MASK, M98925_DAI_IMON_EN_MASK);
+       regmap_update_bits(max98925->regmap,
+               MAX98925_DOUT_CFG_IMON,
+               M98925_DAI_IMON_SLOT_MASK,
+               max98925->i_slot << M98925_DAI_IMON_SLOT_SHIFT);
+}
+
+static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+       unsigned int invert = 0;
+
+       dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* set DAI to slave mode */
+               regmap_update_bits(max98925->regmap,
+                       MAX98925_DAI_CLK_MODE2,
+                       M98925_DAI_MAS_MASK, 0);
+               max98925_set_sense_data(max98925);
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /*
+                * set left channel DAI to master mode,
+                * right channel always slave
+                */
+               regmap_update_bits(max98925->regmap,
+                       MAX98925_DAI_CLK_MODE2,
+                       M98925_DAI_MAS_MASK, M98925_DAI_MAS_MASK);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_CBM_CFS:
+       default:
+               dev_err(codec->dev, "DAI clock mode unsupported");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               invert = M98925_DAI_WCI_MASK;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               invert = M98925_DAI_BCI_MASK;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK;
+               break;
+       default:
+               dev_err(codec->dev, "DAI invert mode unsupported");
+               return -EINVAL;
+       }
+
+       regmap_update_bits(max98925->regmap, MAX98925_FORMAT,
+                       M98925_DAI_BCI_MASK, invert);
+       return 0;
+}
+
+static int max98925_set_clock(struct max98925_priv *max98925,
+               struct snd_pcm_hw_params *params)
+{
+       unsigned int dai_sr = 0, clock, mdll, n, m;
+       struct snd_soc_codec *codec = max98925->codec;
+       int rate = params_rate(params);
+       /* BCLK/LRCLK ratio calculation */
+       int blr_clk_ratio = params_channels(params) * max98925->ch_size;
+
+       switch (blr_clk_ratio) {
+       case 32:
+               regmap_update_bits(max98925->regmap,
+                       MAX98925_DAI_CLK_MODE2,
+                       M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_32);
+               break;
+       case 48:
+               regmap_update_bits(max98925->regmap,
+                       MAX98925_DAI_CLK_MODE2,
+                       M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_48);
+               break;
+       case 64:
+               regmap_update_bits(max98925->regmap,
+                       MAX98925_DAI_CLK_MODE2,
+                       M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_64);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (max98925->sysclk) {
+       case 6000000:
+               clock = 0;
+               mdll  = M98925_MDLL_MULT_MCLKx16;
+               break;
+       case 11289600:
+               clock = 1;
+               mdll  = M98925_MDLL_MULT_MCLKx8;
+               break;
+       case 12000000:
+               clock = 0;
+               mdll  = M98925_MDLL_MULT_MCLKx8;
+               break;
+       case 12288000:
+               clock = 2;
+               mdll  = M98925_MDLL_MULT_MCLKx8;
+               break;
+       default:
+               dev_info(max98925->codec->dev, "unsupported sysclk %d\n",
+                                       max98925->sysclk);
+               return -EINVAL;
+       }
+
+       if (max98925_rate_value(codec, rate, clock, &dai_sr, &n, &m))
+               return -EINVAL;
+
+       /* set DAI_SR to correct LRCLK frequency */
+       regmap_update_bits(max98925->regmap,
+                       MAX98925_DAI_CLK_MODE2,
+                       M98925_DAI_SR_MASK, dai_sr << M98925_DAI_SR_SHIFT);
+       /* set DAI m divider */
+       regmap_write(max98925->regmap,
+               MAX98925_DAI_CLK_DIV_M_MSBS, m >> 8);
+       regmap_write(max98925->regmap,
+               MAX98925_DAI_CLK_DIV_M_LSBS, m & 0xFF);
+       /* set DAI n divider */
+       regmap_write(max98925->regmap,
+               MAX98925_DAI_CLK_DIV_N_MSBS, n >> 8);
+       regmap_write(max98925->regmap,
+               MAX98925_DAI_CLK_DIV_N_LSBS, n & 0xFF);
+       /* set MDLL */
+       regmap_update_bits(max98925->regmap, MAX98925_DAI_CLK_MODE1,
+                       M98925_MDLL_MULT_MASK, mdll << M98925_MDLL_MULT_SHIFT);
+       return 0;
+}
+
+static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+       switch (snd_pcm_format_width(params_format(params))) {
+       case 16:
+               regmap_update_bits(max98925->regmap,
+                               MAX98925_FORMAT,
+                               M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_16);
+               max98925->ch_size = 16;
+               break;
+       case 24:
+               regmap_update_bits(max98925->regmap,
+                               MAX98925_FORMAT,
+                               M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_24);
+               max98925->ch_size = 24;
+               break;
+       case 32:
+               regmap_update_bits(max98925->regmap,
+                               MAX98925_FORMAT,
+                               M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32);
+               max98925->ch_size = 32;
+               break;
+       default:
+               pr_err("%s: format unsupported %d",
+                               __func__, params_format(params));
+               return -EINVAL;
+       }
+       dev_dbg(codec->dev, "%s: format supported %d",
+                               __func__, params_format(params));
+       return max98925_set_clock(max98925, params);
+}
+
+static int max98925_dai_set_sysclk(struct snd_soc_dai *dai,
+                                  int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case 0:
+               /* use MCLK for Left channel, right channel always BCLK */
+               regmap_update_bits(max98925->regmap,
+                               MAX98925_DAI_CLK_MODE1,
+                               M98925_DAI_CLK_SOURCE_MASK, 0);
+               break;
+       case 1:
+               /* configure dai clock source to BCLK instead of MCLK */
+               regmap_update_bits(max98925->regmap,
+                               MAX98925_DAI_CLK_MODE1,
+                               M98925_DAI_CLK_SOURCE_MASK,
+                               M98925_DAI_CLK_SOURCE_MASK);
+               break;
+       default:
+               return -EINVAL;
+       }
+       max98925->sysclk = freq;
+       return 0;
+}
+
+#define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops max98925_dai_ops = {
+       .set_sysclk = max98925_dai_set_sysclk,
+       .set_fmt = max98925_dai_set_fmt,
+       .hw_params = max98925_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98925_dai[] = {
+       {
+               .name = "max98925-aif1",
+               .playback = {
+                       .stream_name = "HiFi Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = MAX98925_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "HiFi Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = MAX98925_FORMATS,
+               },
+               .ops = &max98925_dai_ops,
+       }
+};
+
+static int max98925_probe(struct snd_soc_codec *codec)
+{
+       struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+
+       max98925->codec = codec;
+       codec->control_data = max98925->regmap;
+       regmap_write(max98925->regmap, MAX98925_GLOBAL_ENABLE, 0x00);
+       /* It's not the default but we need to set DAI_DLY */
+       regmap_write(max98925->regmap,
+                       MAX98925_FORMAT, M98925_DAI_DLY_MASK);
+       regmap_write(max98925->regmap, MAX98925_TDM_SLOT_SELECT, 0xC8);
+       regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG1, 0xFF);
+       regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG2, 0xFF);
+       regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG3, 0xFF);
+       regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG4, 0xF0);
+       regmap_write(max98925->regmap, MAX98925_FILTERS, 0xD8);
+       regmap_write(max98925->regmap, MAX98925_ALC_CONFIGURATION, 0xF8);
+       regmap_write(max98925->regmap, MAX98925_CONFIGURATION, 0xF0);
+       /* Disable ALC muting */
+       regmap_write(max98925->regmap, MAX98925_BOOST_LIMITER, 0xF8);
+       return 0;
+}
+
+static const struct snd_soc_codec_driver soc_codec_dev_max98925 = {
+       .probe            = max98925_probe,
+       .controls = max98925_snd_controls,
+       .num_controls = ARRAY_SIZE(max98925_snd_controls),
+       .dapm_routes = max98925_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(max98925_audio_map),
+       .dapm_widgets = max98925_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets),
+};
+
+static const struct regmap_config max98925_regmap = {
+       .reg_bits         = 8,
+       .val_bits         = 8,
+       .max_register     = MAX98925_REV_VERSION,
+       .reg_defaults     = max98925_reg,
+       .num_reg_defaults = ARRAY_SIZE(max98925_reg),
+       .volatile_reg     = max98925_volatile_register,
+       .readable_reg     = max98925_readable_register,
+       .cache_type       = REGCACHE_RBTREE,
+};
+
+static int max98925_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       int ret, reg;
+       u32 value;
+       struct max98925_priv *max98925;
+
+       max98925 = devm_kzalloc(&i2c->dev,
+                       sizeof(*max98925), GFP_KERNEL);
+       if (!max98925)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, max98925);
+       max98925->regmap = devm_regmap_init_i2c(i2c, &max98925_regmap);
+       if (IS_ERR(max98925->regmap)) {
+               ret = PTR_ERR(max98925->regmap);
+               dev_err(&i2c->dev,
+                               "Failed to allocate regmap: %d\n", ret);
+               goto err_out;
+       }
+
+       if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
+               if (value > M98925_DAI_VMON_SLOT_1E_1F) {
+                       dev_err(&i2c->dev, "vmon slot number is wrong:\n");
+                       return -EINVAL;
+               }
+               max98925->v_slot = value;
+       }
+       if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) {
+               if (value > M98925_DAI_IMON_SLOT_1E_1F) {
+                       dev_err(&i2c->dev, "imon slot number is wrong:\n");
+                       return -EINVAL;
+               }
+               max98925->i_slot = value;
+       }
+       ret = regmap_read(max98925->regmap,
+                       MAX98925_REV_VERSION, &reg);
+       if ((ret < 0) ||
+               ((reg != MAX98925_VERSION) &&
+               (reg != MAX98925_VERSION1))) {
+               dev_err(&i2c->dev,
+                       "device initialization error (%d 0x%02X)\n",
+                       ret, reg);
+               goto err_out;
+       }
+       dev_info(&i2c->dev, "device version 0x%02X\n", reg);
+
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98925,
+                       max98925_dai, ARRAY_SIZE(max98925_dai));
+       if (ret < 0)
+               dev_err(&i2c->dev,
+                               "Failed to register codec: %d\n", ret);
+err_out:
+       return ret;
+}
+
+static int max98925_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id max98925_i2c_id[] = {
+       { "max98925", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max98925_i2c_id);
+
+static const struct of_device_id max98925_of_match[] = {
+       { .compatible = "maxim,max98925", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, max98925_of_match);
+
+static struct i2c_driver max98925_i2c_driver = {
+       .driver = {
+               .name = "max98925",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(max98925_of_match),
+               .pm = NULL,
+       },
+       .probe  = max98925_i2c_probe,
+       .remove = max98925_i2c_remove,
+       .id_table = max98925_i2c_id,
+};
+
+module_i2c_driver(max98925_i2c_driver)
+
+MODULE_DESCRIPTION("ALSA SoC MAX98925 driver");
+MODULE_AUTHOR("Ralph Birt <rdbirt@gmail.com>, Anish kumar <anish.kumar@maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98925.h b/sound/soc/codecs/max98925.h
new file mode 100644 (file)
index 0000000..3783248
--- /dev/null
@@ -0,0 +1,832 @@
+/*
+ * max98925.h -- MAX98925 ALSA SoC Audio driver
+ *
+ * Copyright 2013-2015 Maxim Integrated Products
+ *
+ * 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 _MAX98925_H
+#define _MAX98925_H
+
+#define        MAX98925_VERSION        0x51
+#define        MAX98925_VERSION1       0x80
+#define MAX98925_VBAT_DATA             0x00
+#define MAX98925_VBST_DATA             0x01
+#define MAX98925_LIVE_STATUS0          0x02
+#define MAX98925_LIVE_STATUS1          0x03
+#define MAX98925_LIVE_STATUS2          0x04
+#define MAX98925_STATE0                        0x05
+#define MAX98925_STATE1                        0x06
+#define MAX98925_STATE2                        0x07
+#define MAX98925_FLAG0                 0x08
+#define MAX98925_FLAG1                 0x09
+#define MAX98925_FLAG2                 0x0A
+#define MAX98925_IRQ_ENABLE0           0x0B
+#define MAX98925_IRQ_ENABLE1           0x0C
+#define MAX98925_IRQ_ENABLE2           0x0D
+#define MAX98925_IRQ_CLEAR0            0x0E
+#define MAX98925_IRQ_CLEAR1            0x0F
+#define MAX98925_IRQ_CLEAR2            0x10
+#define MAX98925_MAP0                  0x11
+#define MAX98925_MAP1                  0x12
+#define MAX98925_MAP2                  0x13
+#define MAX98925_MAP3                  0x14
+#define MAX98925_MAP4                  0x15
+#define MAX98925_MAP5                  0x16
+#define MAX98925_MAP6                  0x17
+#define MAX98925_MAP7                  0x18
+#define MAX98925_MAP8                  0x19
+#define MAX98925_DAI_CLK_MODE1         0x1A
+#define MAX98925_DAI_CLK_MODE2         0x1B
+#define MAX98925_DAI_CLK_DIV_M_MSBS    0x1C
+#define MAX98925_DAI_CLK_DIV_M_LSBS    0x1D
+#define MAX98925_DAI_CLK_DIV_N_MSBS    0x1E
+#define MAX98925_DAI_CLK_DIV_N_LSBS    0x1F
+#define MAX98925_FORMAT                        0x20
+#define MAX98925_TDM_SLOT_SELECT       0x21
+#define MAX98925_DOUT_CFG_VMON         0x22
+#define MAX98925_DOUT_CFG_IMON         0x23
+#define MAX98925_DOUT_CFG_VBAT         0x24
+#define MAX98925_DOUT_CFG_VBST         0x25
+#define MAX98925_DOUT_CFG_FLAG         0x26
+#define MAX98925_DOUT_HIZ_CFG1         0x27
+#define MAX98925_DOUT_HIZ_CFG2         0x28
+#define MAX98925_DOUT_HIZ_CFG3         0x29
+#define MAX98925_DOUT_HIZ_CFG4         0x2A
+#define MAX98925_DOUT_DRV_STRENGTH     0x2B
+#define MAX98925_FILTERS               0x2C
+#define MAX98925_GAIN                  0x2D
+#define MAX98925_GAIN_RAMPING          0x2E
+#define MAX98925_SPK_AMP               0x2F
+#define MAX98925_THRESHOLD             0x30
+#define MAX98925_ALC_ATTACK            0x31
+#define MAX98925_ALC_ATTEN_RLS         0x32
+#define MAX98925_ALC_HOLD_RLS          0x33
+#define MAX98925_ALC_CONFIGURATION     0x34
+#define MAX98925_BOOST_CONVERTER       0x35
+#define MAX98925_BLOCK_ENABLE          0x36
+#define MAX98925_CONFIGURATION         0x37
+#define MAX98925_GLOBAL_ENABLE         0x38
+#define MAX98925_BOOST_LIMITER         0x3A
+#define MAX98925_REV_VERSION           0xFF
+
+#define MAX98925_REG_CNT               (MAX98925_R03A_BOOST_LIMITER+1)
+
+/* MAX98925 Register Bit Fields */
+
+/* MAX98925_R002_LIVE_STATUS0 */
+#define M98925_THERMWARN_STATUS_MASK                   (1<<3)
+#define M98925_THERMWARN_STATUS_SHIFT                  3
+#define M98925_THERMWARN_STATUS_WIDTH                  1
+#define M98925_THERMSHDN_STATUS_MASK                   (1<<1)
+#define M98925_THERMSHDN_STATUS_SHIFT                  1
+#define M98925_THERMSHDN_STATUS_WIDTH                  1
+
+/* MAX98925_R003_LIVE_STATUS1 */
+#define M98925_SPKCURNT_STATUS_MASK                    (1<<5)
+#define M98925_SPKCURNT_STATUS_SHIFT                   5
+#define M98925_SPKCURNT_STATUS_WIDTH                   1
+#define M98925_WATCHFAIL_STATUS_MASK                   (1<<4)
+#define M98925_WATCHFAIL_STATUS_SHIFT                  4
+#define M98925_WATCHFAIL_STATUS_WIDTH                  1
+#define M98925_ALCINFH_STATUS_MASK                     (1<<3)
+#define M98925_ALCINFH_STATUS_SHIFT                    3
+#define M98925_ALCINFH_STATUS_WIDTH                    1
+#define M98925_ALCACT_STATUS_MASK                      (1<<2)
+#define M98925_ALCACT_STATUS_SHIFT                     2
+#define M98925_ALCACT_STATUS_WIDTH                     1
+#define M98925_ALCMUT_STATUS_MASK                      (1<<1)
+#define M98925_ALCMUT_STATUS_SHIFT                     1
+#define M98925_ALCMUT_STATUS_WIDTH                     1
+#define M98925_ACLP_STATUS_MASK                                (1<<0)
+#define M98925_ACLP_STATUS_SHIFT                       0
+#define M98925_ACLP_STATUS_WIDTH                       1
+
+/* MAX98925_R004_LIVE_STATUS2 */
+#define M98925_SLOTOVRN_STATUS_MASK                    (1<<6)
+#define M98925_SLOTOVRN_STATUS_SHIFT                   6
+#define M98925_SLOTOVRN_STATUS_WIDTH                   1
+#define M98925_INVALSLOT_STATUS_MASK                   (1<<5)
+#define M98925_INVALSLOT_STATUS_SHIFT                  5
+#define M98925_INVALSLOT_STATUS_WIDTH                  1
+#define M98925_SLOTCNFLT_STATUS_MASK                   (1<<4)
+#define M98925_SLOTCNFLT_STATUS_SHIFT                  4
+#define M98925_SLOTCNFLT_STATUS_WIDTH                  1
+#define M98925_VBSTOVFL_STATUS_MASK                    (1<<3)
+#define M98925_VBSTOVFL_STATUS_SHIFT                   3
+#define M98925_VBSTOVFL_STATUS_WIDTH                   1
+#define M98925_VBATOVFL_STATUS_MASK                    (1<<2)
+#define M98925_VBATOVFL_STATUS_SHIFT                   2
+#define M98925_VBATOVFL_STATUS_WIDTH                   1
+#define M98925_IMONOVFL_STATUS_MASK                    (1<<1)
+#define M98925_IMONOVFL_STATUS_SHIFT                   1
+#define M98925_IMONOVFL_STATUS_WIDTH                   1
+#define M98925_VMONOVFL_STATUS_MASK                    (1<<0)
+#define M98925_VMONOVFL_STATUS_SHIFT                   0
+#define M98925_VMONOVFL_STATUS_WIDTH                   1
+
+/* MAX98925_R005_STATE0 */
+#define M98925_THERMWARN_END_STATE_MASK                        (1<<3)
+#define M98925_THERMWARN_END_STATE_SHIFT               3
+#define M98925_THERMWARN_END_STATE_WIDTH               1
+#define M98925_THERMWARN_BGN_STATE_MASK                        (1<<2)
+#define M98925_THERMWARN_BGN_STATE_SHIFT               1
+#define M98925_THERMWARN_BGN_STATE_WIDTH               1
+#define M98925_THERMSHDN_END_STATE_MASK                        (1<<1)
+#define M98925_THERMSHDN_END_STATE_SHIFT               1
+#define M98925_THERMSHDN_END_STATE_WIDTH               1
+#define M98925_THERMSHDN_BGN_STATE_MASK                        (1<<0)
+#define M98925_THERMSHDN_BGN_STATE_SHIFT               0
+#define M98925_THERMSHDN_BGN_STATE_WIDTH               1
+
+/* MAX98925_R006_STATE1 */
+#define M98925_SPRCURNT_STATE_MASK                     (1<<5)
+#define M98925_SPRCURNT_STATE_SHIFT                    5
+#define M98925_SPRCURNT_STATE_WIDTH                    1
+#define M98925_WATCHFAIL_STATE_MASK                    (1<<4)
+#define M98925_WATCHFAIL_STATE_SHIFT                   4
+#define M98925_WATCHFAIL_STATE_WIDTH                   1
+#define M98925_ALCINFH_STATE_MASK                      (1<<3)
+#define M98925_ALCINFH_STATE_SHIFT                     3
+#define M98925_ALCINFH_STATE_WIDTH                     1
+#define M98925_ALCACT_STATE_MASK                       (1<<2)
+#define M98925_ALCACT_STATE_SHIFT                      2
+#define M98925_ALCACT_STATE_WIDTH                      1
+#define M98925_ALCMUT_STATE_MASK                       (1<<1)
+#define M98925_ALCMUT_STATE_SHIFT                      1
+#define M98925_ALCMUT_STATE_WIDTH                      1
+#define M98925_ALCP_STATE_MASK                         (1<<0)
+#define M98925_ALCP_STATE_SHIFT                                0
+#define M98925_ALCP_STATE_WIDTH                                1
+
+/* MAX98925_R007_STATE2 */
+#define M98925_SLOTOVRN_STATE_MASK                     (1<<6)
+#define M98925_SLOTOVRN_STATE_SHIFT                    6
+#define M98925_SLOTOVRN_STATE_WIDTH                    1
+#define M98925_INVALSLOT_STATE_MASK                    (1<<5)
+#define M98925_INVALSLOT_STATE_SHIFT                   5
+#define M98925_INVALSLOT_STATE_WIDTH                   1
+#define M98925_SLOTCNFLT_STATE_MASK                    (1<<4)
+#define M98925_SLOTCNFLT_STATE_SHIFT                   4
+#define M98925_SLOTCNFLT_STATE_WIDTH                   1
+#define M98925_VBSTOVFL_STATE_MASK                     (1<<3)
+#define M98925_VBSTOVFL_STATE_SHIFT                    3
+#define M98925_VBSTOVFL_STATE_WIDTH                    1
+#define M98925_VBATOVFL_STATE_MASK                     (1<<2)
+#define M98925_VBATOVFL_STATE_SHIFT                    2
+#define M98925_VBATOVFL_STATE_WIDTH                    1
+#define M98925_IMONOVFL_STATE_MASK                     (1<<1)
+#define M98925_IMONOVFL_STATE_SHIFT                    1
+#define M98925_IMONOVFL_STATE_WIDTH                    1
+#define M98925_VMONOVFL_STATE_MASK                     (1<<0)
+#define M98925_VMONOVFL_STATE_SHIFT                    0
+#define M98925_VMONOVFL_STATE_WIDTH                    1
+
+/* MAX98925_R008_FLAG0 */
+#define M98925_THERMWARN_END_FLAG_MASK                 (1<<3)
+#define M98925_THERMWARN_END_FLAG_SHIFT                        3
+#define M98925_THERMWARN_END_FLAG_WIDTH                        1
+#define M98925_THERMWARN_BGN_FLAG_MASK                 (1<<2)
+#define M98925_THERMWARN_BGN_FLAG_SHIFT                        2
+#define M98925_THERMWARN_BGN_FLAG_WIDTH                        1
+#define M98925_THERMSHDN_END_FLAG_MASK                 (1<<1)
+#define M98925_THERMSHDN_END_FLAG_SHIFT                        1
+#define M98925_THERMSHDN_END_FLAG_WIDTH                        1
+#define M98925_THERMSHDN_BGN_FLAG_MASK                 (1<<0)
+#define M98925_THERMSHDN_BGN_FLAG_SHIFT                        0
+#define M98925_THERMSHDN_BGN_FLAG_WIDTH                        1
+
+/* MAX98925_R009_FLAG1 */
+#define M98925_SPKCURNT_FLAG_MASK                      (1<<5)
+#define M98925_SPKCURNT_FLAG_SHIFT                     5
+#define M98925_SPKCURNT_FLAG_WIDTH                     1
+#define M98925_WATCHFAIL_FLAG_MASK                     (1<<4)
+#define M98925_WATCHFAIL_FLAG_SHIFT                    4
+#define M98925_WATCHFAIL_FLAG_WIDTH                    1
+#define M98925_ALCINFH_FLAG_MASK                       (1<<3)
+#define M98925_ALCINFH_FLAG_SHIFT                      3
+#define M98925_ALCINFH_FLAG_WIDTH                      1
+#define M98925_ALCACT_FLAG_MASK                                (1<<2)
+#define M98925_ALCACT_FLAG_SHIFT                       2
+#define M98925_ALCACT_FLAG_WIDTH                       1
+#define M98925_ALCMUT_FLAG_MASK                                (1<<1)
+#define M98925_ALCMUT_FLAG_SHIFT                       1
+#define M98925_ALCMUT_FLAG_WIDTH                       1
+#define M98925_ALCP_FLAG_MASK                          (1<<0)
+#define M98925_ALCP_FLAG_SHIFT                         0
+#define M98925_ALCP_FLAG_WIDTH                         1
+
+/* MAX98925_R00A_FLAG2 */
+#define M98925_SLOTOVRN_FLAG_MASK                      (1<<6)
+#define M98925_SLOTOVRN_FLAG_SHIFT                     6
+#define M98925_SLOTOVRN_FLAG_WIDTH                     1
+#define M98925_INVALSLOT_FLAG_MASK                     (1<<5)
+#define M98925_INVALSLOT_FLAG_SHIFT                    5
+#define M98925_INVALSLOT_FLAG_WIDTH                    1
+#define M98925_SLOTCNFLT_FLAG_MASK                     (1<<4)
+#define M98925_SLOTCNFLT_FLAG_SHIFT                    4
+#define M98925_SLOTCNFLT_FLAG_WIDTH                    1
+#define M98925_VBSTOVFL_FLAG_MASK                      (1<<3)
+#define M98925_VBSTOVFL_FLAG_SHIFT                     3
+#define M98925_VBSTOVFL_FLAG_WIDTH                     1
+#define M98925_VBATOVFL_FLAG_MASK                      (1<<2)
+#define M98925_VBATOVFL_FLAG_SHIFT                     2
+#define M98925_VBATOVFL_FLAG_WIDTH                     1
+#define M98925_IMONOVFL_FLAG_MASK                      (1<<1)
+#define M98925_IMONOVFL_FLAG_SHIFT                     1
+#define M98925_IMONOVFL_FLAG_WIDTH                     1
+#define M98925_VMONOVFL_FLAG_MASK                      (1<<0)
+#define M98925_VMONOVFL_FLAG_SHIFT                     0
+#define M98925_VMONOVFL_FLAG_WIDTH                     1
+
+/* MAX98925_R00B_IRQ_ENABLE0 */
+#define M98925_THERMWARN_END_EN_MASK                   (1<<3)
+#define M98925_THERMWARN_END_EN_SHIFT                  3
+#define M98925_THERMWARN_END_EN_WIDTH                  1
+#define M98925_THERMWARN_BGN_EN_MASK                   (1<<2)
+#define M98925_THERMWARN_BGN_EN_SHIFT                  2
+#define M98925_THERMWARN_BGN_EN_WIDTH                  1
+#define M98925_THERMSHDN_END_EN_MASK                   (1<<1)
+#define M98925_THERMSHDN_END_EN_SHIFT                  1
+#define M98925_THERMSHDN_END_EN_WIDTH                  1
+#define M98925_THERMSHDN_BGN_EN_MASK                   (1<<0)
+#define M98925_THERMSHDN_BGN_EN_SHIFT                  0
+#define M98925_THERMSHDN_BGN_EN_WIDTH                  1
+
+/* MAX98925_R00C_IRQ_ENABLE1 */
+#define M98925_SPKCURNT_EN_MASK                                (1<<5)
+#define M98925_SPKCURNT_EN_SHIFT                       5
+#define M98925_SPKCURNT_EN_WIDTH                       1
+#define M98925_WATCHFAIL_EN_MASK                       (1<<4)
+#define M98925_WATCHFAIL_EN_SHIFT                      4
+#define M98925_WATCHFAIL_EN_WIDTH                      1
+#define M98925_ALCINFH_EN_MASK                         (1<<3)
+#define M98925_ALCINFH_EN_SHIFT                                3
+#define M98925_ALCINFH_EN_WIDTH                                1
+#define M98925_ALCACT_EN_MASK                          (1<<2)
+#define M98925_ALCACT_EN_SHIFT                         2
+#define M98925_ALCACT_EN_WIDTH                         1
+#define M98925_ALCMUT_EN_MASK                          (1<<1)
+#define M98925_ALCMUT_EN_SHIFT                         1
+#define M98925_ALCMUT_EN_WIDTH                         1
+#define M98925_ALCP_EN_MASK                                    (1<<0)
+#define M98925_ALCP_EN_SHIFT                           0
+#define M98925_ALCP_EN_WIDTH                           1
+
+/* MAX98925_R00D_IRQ_ENABLE2 */
+#define M98925_SLOTOVRN_EN_MASK                                        (1<<6)
+#define M98925_SLOTOVRN_EN_SHIFT                               6
+#define M98925_SLOTOVRN_EN_WIDTH                               1
+#define M98925_INVALSLOT_EN_MASK                               (1<<5)
+#define M98925_INVALSLOT_EN_SHIFT                              5
+#define M98925_INVALSLOT_EN_WIDTH                              1
+#define M98925_SLOTCNFLT_EN_MASK                               (1<<4)
+#define M98925_SLOTCNFLT_EN_SHIFT                              4
+#define M98925_SLOTCNFLT_EN_WIDTH                              1
+#define M98925_VBSTOVFL_EN_MASK                                        (1<<3)
+#define M98925_VBSTOVFL_EN_SHIFT                               3
+#define M98925_VBSTOVFL_EN_WIDTH                               1
+#define M98925_VBATOVFL_EN_MASK                                        (1<<2)
+#define M98925_VBATOVFL_EN_SHIFT                               2
+#define M98925_VBATOVFL_EN_WIDTH                               1
+#define M98925_IMONOVFL_EN_MASK                                        (1<<1)
+#define M98925_IMONOVFL_EN_SHIFT                               1
+#define M98925_IMONOVFL_EN_WIDTH                               1
+#define M98925_VMONOVFL_EN_MASK                                        (1<<0)
+#define M98925_VMONOVFL_EN_SHIFT                               0
+#define M98925_VMONOVFL_EN_WIDTH                               1
+
+/* MAX98925_R00E_IRQ_CLEAR0 */
+#define M98925_THERMWARN_END_CLR_MASK                  (1<<3)
+#define M98925_THERMWARN_END_CLR_SHIFT                 3
+#define M98925_THERMWARN_END_CLR_WIDTH                 1
+#define M98925_THERMWARN_BGN_CLR_MASK                  (1<<2)
+#define M98925_THERMWARN_BGN_CLR_SHIFT                 2
+#define M98925_THERMWARN_BGN_CLR_WIDTH                 1
+#define M98925_THERMSHDN_END_CLR_MASK                  (1<<1)
+#define M98925_THERMSHDN_END_CLR_SHIFT                 1
+#define M98925_THERMSHDN_END_CLR_WIDTH                 1
+#define M98925_THERMSHDN_BGN_CLR_MASK                  (1<<0)
+#define M98925_THERMSHDN_BGN_CLR_SHIFT                 0
+#define M98925_THERMSHDN_BGN_CLR_WIDTH                 1
+
+/* MAX98925_R00F_IRQ_CLEAR1 */
+#define M98925_SPKCURNT_CLR_MASK                               (1<<5)
+#define M98925_SPKCURNT_CLR_SHIFT                              5
+#define M98925_SPKCURNT_CLR_WIDTH                              1
+#define M98925_WATCHFAIL_CLR_MASK                              (1<<4)
+#define M98925_WATCHFAIL_CLR_SHIFT                             4
+#define M98925_WATCHFAIL_CLR_WIDTH                             1
+#define M98925_ALCINFH_CLR_MASK                                        (1<<3)
+#define M98925_ALCINFH_CLR_SHIFT                               3
+#define M98925_ALCINFH_CLR_WIDTH                               1
+#define M98925_ALCACT_CLR_MASK                                 (1<<2)
+#define M98925_ALCACT_CLR_SHIFT                                        2
+#define M98925_ALCACT_CLR_WIDTH                                        1
+#define M98925_ALCMUT_CLR_MASK                                 (1<<1)
+#define M98925_ALCMUT_CLR_SHIFT                                        1
+#define M98925_ALCMUT_CLR_WIDTH                                        1
+#define M98925_ALCP_CLR_MASK                                   (1<<0)
+#define M98925_ALCP_CLR_SHIFT                                  0
+#define M98925_ALCP_CLR_WIDTH                                  1
+
+/* MAX98925_R010_IRQ_CLEAR2 */
+#define M98925_SLOTOVRN_CLR_MASK                               (1<<6)
+#define M98925_SLOTOVRN_CLR_SHIFT                              6
+#define M98925_SLOTOVRN_CLR_WIDTH                              1
+#define M98925_INVALSLOT_CLR_MASK                              (1<<5)
+#define M98925_INVALSLOT_CLR_SHIFT                             5
+#define M98925_INVALSLOT_CLR_WIDTH                             1
+#define M98925_SLOTCNFLT_CLR_MASK                              (1<<4)
+#define M98925_SLOTCNFLT_CLR_SHIFT                             4
+#define M98925_SLOTCNFLT_CLR_WIDTH                             1
+#define M98925_VBSTOVFL_CLR_MASK                               (1<<3)
+#define M98925_VBSTOVFL_CLR_SHIFT                              3
+#define M98925_VBSTOVFL_CLR_WIDTH                              1
+#define M98925_VBATOVFL_CLR_MASK                               (1<<2)
+#define M98925_VBATOVFL_CLR_SHIFT                              2
+#define M98925_VBATOVFL_CLR_WIDTH                              1
+#define M98925_IMONOVFL_CLR_MASK                               (1<<1)
+#define M98925_IMONOVFL_CLR_SHIFT                              1
+#define M98925_IMONOVFL_CLR_WIDTH                              1
+#define M98925_VMONOVFL_CLR_MASK                               (1<<0)
+#define M98925_VMONOVFL_CLR_SHIFT                              0
+#define M98925_VMONOVFL_CLR_WIDTH                              1
+
+/* MAX98925_R011_MAP0 */
+#define M98925_ER_THERMWARN_EN_MASK                            (1<<7)
+#define M98925_ER_THERMWARN_EN_SHIFT                   7
+#define M98925_ER_THERMWARN_EN_WIDTH                   1
+#define M98925_ER_THERMWARN_MAP_MASK                   (0x07<<4)
+#define M98925_ER_THERMWARN_MAP_SHIFT                  4
+#define M98925_ER_THERMWARN_MAP_WIDTH                  3
+
+/* MAX98925_R012_MAP1 */
+#define M98925_ER_ALCMUT_EN_MASK                               (1<<7)
+#define M98925_ER_ALCMUT_EN_SHIFT                              7
+#define M98925_ER_ALCMUT_EN_WIDTH                              1
+#define M98925_ER_ALCMUT_MAP_MASK                              (0x07<<4)
+#define M98925_ER_ALCMUT_MAP_SHIFT                             4
+#define M98925_ER_ALCMUT_MAP_WIDTH                             3
+#define M98925_ER_ALCP_EN_MASK                                 (1<<3)
+#define M98925_ER_ALCP_EN_SHIFT                                        3
+#define M98925_ER_ALCP_EN_WIDTH                                        1
+#define M98925_ER_ALCP_MAP_MASK                                        (0x07<<0)
+#define M98925_ER_ALCP_MAP_SHIFT                               0
+#define M98925_ER_ALCP_MAP_WIDTH                               3
+
+/* MAX98925_R013_MAP2 */
+#define M98925_ER_ALCINFH_EN_MASK                              (1<<7)
+#define M98925_ER_ALCINFH_EN_SHIFT                             7
+#define M98925_ER_ALCINFH_EN_WIDTH                             1
+#define M98925_ER_ALCINFH_MAP_MASK                             (0x07<<4)
+#define M98925_ER_ALCINFH_MAP_SHIFT                            4
+#define M98925_ER_ALCINFH_MAP_WIDTH                            3
+#define M98925_ER_ALCACT_EN_MASK                               (1<<3)
+#define M98925_ER_ALCACT_EN_SHIFT                              3
+#define M98925_ER_ALCACT_EN_WIDTH                              1
+#define M98925_ER_ALCACT_MAP_MASK                              (0x07<<0)
+#define M98925_ER_ALCACT_MAP_SHIFT                             0
+#define M98925_ER_ALCACT_MAP_WIDTH                             3
+
+/* MAX98925_R014_MAP3 */
+#define M98925_ER_SPKCURNT_EN_MASK                             (1<<7)
+#define M98925_ER_SPKCURNT_EN_SHIFT                            7
+#define M98925_ER_SPKCURNT_EN_WIDTH                            1
+#define M98925_ER_SPKCURNT_MAP_MASK                            (0x07<<4)
+#define M98925_ER_SPKCURNT_MAP_SHIFT                   4
+#define M98925_ER_SPKCURNT_MAP_WIDTH                   3
+
+/* MAX98925_R015_MAP4 */
+/* RESERVED */
+
+/* MAX98925_R016_MAP5 */
+#define M98925_ER_IMONOVFL_EN_MASK                             (1<<7)
+#define M98925_ER_IMONOVFL_EN_SHIFT                            7
+#define M98925_ER_IMONOVFL_EN_WIDTH                            1
+#define M98925_ER_IMONOVFL_MAP_MASK                            (0x07<<4)
+#define M98925_ER_IMONOVFL_MAP_SHIFT                   4
+#define M98925_ER_IMONOVFL_MAP_WIDTH                   3
+#define M98925_ER_VMONOVFL_EN_MASK                             (1<<3)
+#define M98925_ER_VMONOVFL_EN_SHIFT                            3
+#define M98925_ER_VMONOVFL_EN_WIDTH                            1
+#define M98925_ER_VMONOVFL_MAP_MASK                            (0x07<<0)
+#define M98925_ER_VMONOVFL_MAP_SHIFT                   0
+#define M98925_ER_VMONOVFL_MAP_WIDTH                   3
+
+/* MAX98925_R017_MAP6 */
+#define M98925_ER_VBSTOVFL_EN_MASK                             (1<<7)
+#define M98925_ER_VBSTOVFL_EN_SHIFT                            7
+#define M98925_ER_VBSTOVFL_EN_WIDTH                            1
+#define M98925_ER_VBSTOVFL_MAP_MASK                            (0x07<<4)
+#define M98925_ER_VBSTOVFL_MAP_SHIFT                   4
+#define M98925_ER_VBSTOVFL_MAP_WIDTH                   3
+#define M98925_ER_VBATOVFL_EN_MASK                             (1<<3)
+#define M98925_ER_VBATOVFL_EN_SHIFT                            3
+#define M98925_ER_VBATOVFL_EN_WIDTH                            1
+#define M98925_ER_VBATOVFL_MAP_MASK                            (0x07<<0)
+#define M98925_ER_VBATOVFL_MAP_SHIFT                   0
+#define M98925_ER_VBATOVFL_MAP_WIDTH                   3
+
+/* MAX98925_R018_MAP7 */
+#define M98925_ER_INVALSLOT_EN_MASK                            (1<<7)
+#define M98925_ER_INVALSLOT_EN_SHIFT                   7
+#define M98925_ER_INVALSLOT_EN_WIDTH                   1
+#define M98925_ER_INVALSLOT_MAP_MASK                   (0x07<<4)
+#define M98925_ER_INVALSLOT_MAP_SHIFT                  4
+#define M98925_ER_INVALSLOT_MAP_WIDTH                  3
+#define M98925_ER_SLOTCNFLT_EN_MASK                            (1<<3)
+#define M98925_ER_SLOTCNFLT_EN_SHIFT                   3
+#define M98925_ER_SLOTCNFLT_EN_WIDTH                   1
+#define M98925_ER_SLOTCNFLT_MAP_MASK                   (0x07<<0)
+#define M98925_ER_SLOTCNFLT_MAP_SHIFT                  0
+#define M98925_ER_SLOTCNFLT_MAP_WIDTH                  3
+
+/* MAX98925_R019_MAP8 */
+#define M98925_ER_SLOTOVRN_EN_MASK     (1<<3)
+#define M98925_ER_SLOTOVRN_EN_SHIFT    3
+#define M98925_ER_SLOTOVRN_EN_WIDTH    1
+#define M98925_ER_SLOTOVRN_MAP_MASK    (0x07<<0)
+#define M98925_ER_SLOTOVRN_MAP_SHIFT   0
+#define M98925_ER_SLOTOVRN_MAP_WIDTH   3
+
+/* MAX98925_R01A_DAI_CLK_MODE1 */
+#define M98925_DAI_CLK_SOURCE_MASK     (1<<6)
+#define M98925_DAI_CLK_SOURCE_SHIFT    6
+#define M98925_DAI_CLK_SOURCE_WIDTH    1
+#define M98925_MDLL_MULT_MASK          (0x0F<<0)
+#define M98925_MDLL_MULT_SHIFT         0
+#define M98925_MDLL_MULT_WIDTH         4
+
+#define M98925_MDLL_MULT_MCLKx8                6
+#define M98925_MDLL_MULT_MCLKx16       8
+
+/* MAX98925_R01B_DAI_CLK_MODE2 */
+#define M98925_DAI_SR_MASK                     (0x0F<<4)
+#define M98925_DAI_SR_SHIFT                    4
+#define M98925_DAI_SR_WIDTH                    4
+#define M98925_DAI_MAS_MASK                    (1<<3)
+#define M98925_DAI_MAS_SHIFT                   3
+#define M98925_DAI_MAS_WIDTH                   1
+#define M98925_DAI_BSEL_MASK                   (0x07<<0)
+#define M98925_DAI_BSEL_SHIFT                  0
+#define M98925_DAI_BSEL_WIDTH                  3
+
+#define M98925_DAI_BSEL_32 (0 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_48 (1 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_64 (2 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_256 (6 << M98925_DAI_BSEL_SHIFT)
+
+/* MAX98925_R01C_DAI_CLK_DIV_M_MSBS */
+#define M98925_DAI_M_MSBS_MASK                                 (0xFF<<0)
+#define M98925_DAI_M_MSBS_SHIFT                                        0
+#define M98925_DAI_M_MSBS_WIDTH                                        8
+
+/* MAX98925_R01D_DAI_CLK_DIV_M_LSBS */
+#define M98925_DAI_M_LSBS_MASK                                 (0xFF<<0)
+#define M98925_DAI_M_LSBS_SHIFT                                        0
+#define M98925_DAI_M_LSBS_WIDTH                                        8
+
+/* MAX98925_R01E_DAI_CLK_DIV_N_MSBS */
+#define M98925_DAI_N_MSBS_MASK                                 (0x7F<<0)
+#define M98925_DAI_N_MSBS_SHIFT                                        0
+#define M98925_DAI_N_MSBS_WIDTH                                        7
+
+/* MAX98925_R01F_DAI_CLK_DIV_N_LSBS */
+#define M98925_DAI_N_LSBS_MASK                                 (0xFF<<0)
+#define M98925_DAI_N_LSBS_SHIFT                                        0
+#define M98925_DAI_N_LSBS_WIDTH                                        8
+
+/* MAX98925_R020_FORMAT */
+#define M98925_DAI_CHANSZ_MASK                                 (0x03<<6)
+#define M98925_DAI_CHANSZ_SHIFT                                        6
+#define M98925_DAI_CHANSZ_WIDTH                                        2
+#define M98925_DAI_EXTBCLK_HIZ_MASK                            (1<<4)
+#define M98925_DAI_EXTBCLK_HIZ_SHIFT                   4
+#define M98925_DAI_EXTBCLK_HIZ_WIDTH                   1
+#define M98925_DAI_WCI_MASK                                            (1<<3)
+#define M98925_DAI_WCI_SHIFT                                   3
+#define M98925_DAI_WCI_WIDTH                                   1
+#define M98925_DAI_BCI_MASK                                            (1<<2)
+#define M98925_DAI_BCI_SHIFT                                   2
+#define M98925_DAI_BCI_WIDTH                                   1
+#define M98925_DAI_DLY_MASK                                            (1<<1)
+#define M98925_DAI_DLY_SHIFT                                   1
+#define M98925_DAI_DLY_WIDTH                                   1
+#define M98925_DAI_TDM_MASK                                            (1<<0)
+#define M98925_DAI_TDM_SHIFT                                   0
+#define M98925_DAI_TDM_WIDTH                                   1
+
+#define M98925_DAI_CHANSZ_16 (1 << M98925_DAI_CHANSZ_SHIFT)
+#define M98925_DAI_CHANSZ_24 (2 << M98925_DAI_CHANSZ_SHIFT)
+#define M98925_DAI_CHANSZ_32 (3 << M98925_DAI_CHANSZ_SHIFT)
+
+/* MAX98925_R021_TDM_SLOT_SELECT */
+#define M98925_DAI_DO_EN_MASK                                  (1<<7)
+#define M98925_DAI_DO_EN_SHIFT                                 7
+#define M98925_DAI_DO_EN_WIDTH                                 1
+#define M98925_DAI_DIN_EN_MASK                                 (1<<6)
+#define M98925_DAI_DIN_EN_SHIFT                                        6
+#define M98925_DAI_DIN_EN_WIDTH                                        1
+#define M98925_DAI_INR_SOURCE_MASK                             (0x07<<3)
+#define M98925_DAI_INR_SOURCE_SHIFT                            3
+#define M98925_DAI_INR_SOURCE_WIDTH                            3
+#define M98925_DAI_INL_SOURCE_MASK                             (0x07<<0)
+#define M98925_DAI_INL_SOURCE_SHIFT                            0
+#define M98925_DAI_INL_SOURCE_WIDTH                            3
+
+/* MAX98925_R022_DOUT_CFG_VMON */
+#define M98925_DAI_VMON_EN_MASK                                        (1<<5)
+#define M98925_DAI_VMON_EN_SHIFT                               5
+#define M98925_DAI_VMON_EN_WIDTH                               1
+#define M98925_DAI_VMON_SLOT_MASK                              (0x1F<<0)
+#define M98925_DAI_VMON_SLOT_SHIFT                             0
+#define M98925_DAI_VMON_SLOT_WIDTH                             5
+
+#define M98925_DAI_VMON_SLOT_00_01 (0 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_01_02 (1 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_02_03 (2 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_03_04 (3 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_04_05 (4 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_05_06 (5 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_06_07 (6 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_07_08 (7 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_08_09 (8 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_09_0A (9 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0A_0B (10 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0B_0C (11 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0C_0D (12 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0D_0E (13 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0E_0F (14 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0F_10 (15 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_10_11 (16 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_11_12 (17 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_12_13 (18 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_13_14 (19 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_14_15 (20 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_15_16 (21 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_16_17 (22 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_17_18 (23 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_18_19 (24 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_19_1A (25 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1A_1B (26 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1B_1C (27 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1C_1D (28 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1D_1E (29 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1E_1F (30 << M98925_DAI_VMON_SLOT_SHIFT)
+
+/* MAX98925_R023_DOUT_CFG_IMON */
+#define M98925_DAI_IMON_EN_MASK                                        (1<<5)
+#define M98925_DAI_IMON_EN_SHIFT                               5
+#define M98925_DAI_IMON_EN_WIDTH                               1
+#define M98925_DAI_IMON_SLOT_MASK                              (0x1F<<0)
+#define M98925_DAI_IMON_SLOT_SHIFT                             0
+#define M98925_DAI_IMON_SLOT_WIDTH                             5
+
+#define M98925_DAI_IMON_SLOT_00_01 (0 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_01_02 (1 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_02_03 (2 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_03_04 (3 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_04_05 (4 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_05_06 (5 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_06_07 (6 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_07_08 (7 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_08_09 (8 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_09_0A (9 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0A_0B (10 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0B_0C (11 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0C_0D (12 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0D_0E (13 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0E_0F (14 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0F_10 (15 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_10_11 (16 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_11_12 (17 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_12_13 (18 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_13_14 (19 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_14_15 (20 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_15_16 (21 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_16_17 (22 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_17_18 (23 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_18_19 (24 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_19_1A (25 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1A_1B (26 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1B_1C (27 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1C_1D (28 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1D_1E (29 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1E_1F (30 << M98925_DAI_IMON_SLOT_SHIFT)
+
+/* MAX98925_R024_DOUT_CFG_VBAT */
+#define M98925_DAI_VBAT_EN_MASK                                        (1<<5)
+#define M98925_DAI_VBAT_EN_SHIFT                               5
+#define M98925_DAI_VBAT_EN_WIDTH                               1
+#define M98925_DAI_VBAT_SLOT_MASK                              (0x1F<<0)
+#define M98925_DAI_VBAT_SLOT_SHIFT                             0
+#define M98925_DAI_VBAT_SLOT_WIDTH                             5
+
+/* MAX98925_R025_DOUT_CFG_VBST */
+#define M98925_DAI_VBST_EN_MASK                                        (1<<5)
+#define M98925_DAI_VBST_EN_SHIFT                               5
+#define M98925_DAI_VBST_EN_WIDTH                               1
+#define M98925_DAI_VBST_SLOT_MASK                              (0x1F<<0)
+#define M98925_DAI_VBST_SLOT_SHIFT                             0
+#define M98925_DAI_VBST_SLOT_WIDTH                             5
+
+/* MAX98925_R026_DOUT_CFG_FLAG */
+#define M98925_DAI_FLAG_EN_MASK                                        (1<<5)
+#define M98925_DAI_FLAG_EN_SHIFT                               5
+#define M98925_DAI_FLAG_EN_WIDTH                               1
+#define M98925_DAI_FLAG_SLOT_MASK                              (0x1F<<0)
+#define M98925_DAI_FLAG_SLOT_SHIFT                             0
+#define M98925_DAI_FLAG_SLOT_WIDTH                             5
+
+/* MAX98925_R027_DOUT_HIZ_CFG1 */
+#define M98925_DAI_SLOT_HIZ_CFG1_MASK                  (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG1_SHIFT                 0
+#define M98925_DAI_SLOT_HIZ_CFG1_WIDTH                 8
+
+/* MAX98925_R028_DOUT_HIZ_CFG2 */
+#define M98925_DAI_SLOT_HIZ_CFG2_MASK                  (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG2_SHIFT                 0
+#define M98925_DAI_SLOT_HIZ_CFG2_WIDTH                 8
+
+/* MAX98925_R029_DOUT_HIZ_CFG3 */
+#define M98925_DAI_SLOT_HIZ_CFG3_MASK                  (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG3_SHIFT                 0
+#define M98925_DAI_SLOT_HIZ_CFG3_WIDTH                 8
+
+/* MAX98925_R02A_DOUT_HIZ_CFG4 */
+#define M98925_DAI_SLOT_HIZ_CFG4_MASK                  (0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG4_SHIFT                 0
+#define M98925_DAI_SLOT_HIZ_CFG4_WIDTH                 8
+
+/* MAX98925_R02B_DOUT_DRV_STRENGTH */
+#define M98925_DAI_OUT_DRIVE_MASK                              (0x03<<0)
+#define M98925_DAI_OUT_DRIVE_SHIFT                             0
+#define M98925_DAI_OUT_DRIVE_WIDTH                             2
+
+/* MAX98925_R02C_FILTERS */
+#define M98925_ADC_DITHER_EN_MASK                              (1<<7)
+#define M98925_ADC_DITHER_EN_SHIFT                             7
+#define M98925_ADC_DITHER_EN_WIDTH                             1
+#define M98925_IV_DCB_EN_MASK                                  (1<<6)
+#define M98925_IV_DCB_EN_SHIFT                                 6
+#define M98925_IV_DCB_EN_WIDTH                                 1
+#define M98925_DAC_DITHER_EN_MASK                              (1<<4)
+#define M98925_DAC_DITHER_EN_SHIFT                             4
+#define M98925_DAC_DITHER_EN_WIDTH                             1
+#define M98925_DAC_FILTER_MODE_MASK                            (1<<3)
+#define M98925_DAC_FILTER_MODE_SHIFT                   3
+#define M98925_DAC_FILTER_MODE_WIDTH                   1
+#define M98925_DAC_HPF_MASK                            (0x07<<0)
+#define M98925_DAC_HPF_SHIFT                                   0
+#define M98925_DAC_HPF_WIDTH                                   3
+#define M98925_DAC_HPF_DISABLE         (0 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_DC_BLOCK                (1 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_100          (2 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_200          (3 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_400          (4 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_800          (5 << M98925_DAC_HPF_SHIFT)
+
+/* MAX98925_R02D_GAIN */
+#define M98925_DAC_IN_SEL_MASK                                 (0x03<<5)
+#define M98925_DAC_IN_SEL_SHIFT                                        5
+#define M98925_DAC_IN_SEL_WIDTH                                        2
+#define M98925_SPK_GAIN_MASK                                   (0x1F<<0)
+#define M98925_SPK_GAIN_SHIFT                                  0
+#define M98925_SPK_GAIN_WIDTH                                  5
+
+#define M98925_DAC_IN_SEL_LEFT_DAI (0 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_RIGHT_DAI (1 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_SUMMED_DAI (2 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_DIV2_SUMMED_DAI (3 << M98925_DAC_IN_SEL_SHIFT)
+
+/* MAX98925_R02E_GAIN_RAMPING */
+#define M98925_SPK_RMP_EN_MASK         (1<<1)
+#define M98925_SPK_RMP_EN_SHIFT                1
+#define M98925_SPK_RMP_EN_WIDTH                1
+#define M98925_SPK_ZCD_EN_MASK         (1<<0)
+#define M98925_SPK_ZCD_EN_SHIFT                0
+#define M98925_SPK_ZCD_EN_WIDTH                1
+
+/* MAX98925_R02F_SPK_AMP */
+#define M98925_SPK_MODE_MASK           (1<<0)
+#define M98925_SPK_MODE_SHIFT          0
+#define M98925_SPK_MODE_WIDTH          1
+
+/* MAX98925_R030_THRESHOLD */
+#define M98925_ALC_EN_MASK                     (1<<5)
+#define M98925_ALC_EN_SHIFT                    5
+#define M98925_ALC_EN_WIDTH                    1
+#define M98925_ALC_TH_MASK                     (0x1F<<0)
+#define M98925_ALC_TH_SHIFT                    0
+#define M98925_ALC_TH_WIDTH                    5
+
+/* MAX98925_R031_ALC_ATTACK */
+#define M98925_ALC_ATK_STEP_MASK       (0x0F<<4)
+#define M98925_ALC_ATK_STEP_SHIFT      4
+#define M98925_ALC_ATK_STEP_WIDTH      4
+#define M98925_ALC_ATK_RATE_MASK       (0x7<<0)
+#define M98925_ALC_ATK_RATE_SHIFT      0
+#define M98925_ALC_ATK_RATE_WIDTH      3
+
+/* MAX98925_R032_ALC_ATTEN_RLS */
+#define M98925_ALC_MAX_ATTEN_MASK      (0x0F<<4)
+#define M98925_ALC_MAX_ATTEN_SHIFT     4
+#define M98925_ALC_MAX_ATTEN_WIDTH     4
+#define M98925_ALC_RLS_RATE_MASK       (0x7<<0)
+#define M98925_ALC_RLS_RATE_SHIFT      0
+#define M98925_ALC_RLS_RATE_WIDTH      3
+
+/* MAX98925_R033_ALC_HOLD_RLS */
+#define M98925_ALC_RLS_TGR_MASK                (1<<0)
+#define M98925_ALC_RLS_TGR_SHIFT       0
+#define M98925_ALC_RLS_TGR_WIDTH       1
+
+/* MAX98925_R034_ALC_CONFIGURATION */
+#define M98925_ALC_MUTE_EN_MASK                (1<<7)
+#define M98925_ALC_MUTE_EN_SHIFT       7
+#define M98925_ALC_MUTE_EN_WIDTH       1
+#define M98925_ALC_MUTE_DLY_MASK       (0x07<<4)
+#define M98925_ALC_MUTE_DLY_SHIFT      4
+#define M98925_ALC_MUTE_DLY_WIDTH      3
+#define M98925_ALC_RLS_DBT_MASK                (0x07<<0)
+#define M98925_ALC_RLS_DBT_SHIFT       0
+#define M98925_ALC_RLS_DBT_WIDTH       3
+
+/* MAX98925_R035_BOOST_CONVERTER */
+#define M98925_BST_SYNC_MASK           (1<<7)
+#define M98925_BST_SYNC_SHIFT          7
+#define M98925_BST_SYNC_WIDTH          1
+#define M98925_BST_PHASE_MASK          (0x03<<4)
+#define M98925_BST_PHASE_SHIFT         4
+#define M98925_BST_PHASE_WIDTH         2
+#define M98925_BST_SKIP_MODE_MASK      (0x03<<0)
+#define M98925_BST_SKIP_MODE_SHIFT     0
+#define M98925_BST_SKIP_MODE_WIDTH     2
+
+/* MAX98925_R036_BLOCK_ENABLE */
+#define M98925_BST_EN_MASK                     (1<<7)
+#define M98925_BST_EN_SHIFT                    7
+#define M98925_BST_EN_WIDTH                    1
+#define M98925_WATCH_EN_MASK           (1<<6)
+#define M98925_WATCH_EN_SHIFT          6
+#define M98925_WATCH_EN_WIDTH          1
+#define M98925_CLKMON_EN_MASK          (1<<5)
+#define M98925_CLKMON_EN_SHIFT         5
+#define M98925_CLKMON_EN_WIDTH         1
+#define M98925_SPK_EN_MASK                     (1<<4)
+#define M98925_SPK_EN_SHIFT                    4
+#define M98925_SPK_EN_WIDTH                    1
+#define M98925_ADC_VBST_EN_MASK                (1<<3)
+#define M98925_ADC_VBST_EN_SHIFT       3
+#define M98925_ADC_VBST_EN_WIDTH       1
+#define M98925_ADC_VBAT_EN_MASK                (1<<2)
+#define M98925_ADC_VBAT_EN_SHIFT       2
+#define M98925_ADC_VBAT_EN_WIDTH       1
+#define M98925_ADC_IMON_EN_MASK                (1<<1)
+#define M98925_ADC_IMON_EN_SHIFT       1
+#define M98925_ADC_IMON_EN_WIDTH       1
+#define M98925_ADC_VMON_EN_MASK                (1<<0)
+#define M98925_ADC_VMON_EN_SHIFT       0
+#define M98925_ADC_VMON_EN_WIDTH       1
+
+/* MAX98925_R037_CONFIGURATION */
+#define M98925_BST_VOUT_MASK           (0x0F<<4)
+#define M98925_BST_VOUT_SHIFT          4
+#define M98925_BST_VOUT_WIDTH          4
+#define M98925_THERMWARN_LEVEL_MASK    (0x03<<2)
+#define M98925_THERMWARN_LEVEL_SHIFT                   2
+#define M98925_THERMWARN_LEVEL_WIDTH                   2
+#define M98925_WATCH_TIME_MASK                 (0x03<<0)
+#define M98925_WATCH_TIME_SHIFT                        0
+#define M98925_WATCH_TIME_WIDTH                        2
+
+/* MAX98925_R038_GLOBAL_ENABLE */
+#define M98925_EN_MASK                 (1<<7)
+#define M98925_EN_SHIFT                        7
+#define M98925_EN_WIDTH                        1
+
+/* MAX98925_R03A_BOOST_LIMITER */
+#define M98925_BST_ILIM_MASK   (0x1F<<3)
+#define M98925_BST_ILIM_SHIFT  3
+#define M98925_BST_ILIM_WIDTH  5
+
+/* MAX98925_R0FF_VERSION */
+#define M98925_REV_ID_MASK     (0xFF<<0)
+#define M98925_REV_ID_SHIFT    0
+#define M98925_REV_ID_WIDTH    8
+
+struct max98925_priv {
+       struct regmap *regmap;
+       struct snd_soc_codec *codec;
+       struct max98925_pdata *pdata;
+       unsigned int sysclk;
+       unsigned int v_slot;
+       unsigned int i_slot;
+       unsigned int spk_gain;
+       unsigned int ch_size;
+};
+#endif
index a722a023c26280a3c89f7a198e95c818f0c2fe6a..477e13d309713e56a5a4416d054350185fea0007 100644 (file)
@@ -118,7 +118,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = priv->deemph;
+       ucontrol->value.integer.value[0] = priv->deemph;
 
        return 0;
 }
@@ -129,7 +129,7 @@ static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       priv->deemph = ucontrol->value.enumerated.item[0];
+       priv->deemph = ucontrol->value.integer.value[0];
 
        return pcm1681_set_deemph(codec);
 }
index 9974f201a08f44ee25b109c7ff78e13440146c4b..5a30fdd0da00b0eb0d1d34859565704b393faf70 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 f374840a5a7ce376272d8f7e3290f91c099cb19f..826037090c8385cf9a2ddaf255052051390f377d 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 c9a4c5be083b454230c1a0d9bf0424fd8c279056..69528ae5410c991125c2e16f3810d51ae7026b88 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 dbfd98c22f4dea617b48b7fbbf214452421bd13e..db78e9462876978e7a3a3917c31c982a487f5fbd 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 e1a4a45c57e229b12dcd174ac8453f8772b6e3b1..cc7f84a150a7f03878795a7a96f991a6db5b1de5 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 21f8e18c13c48d606deb315b6abc82838029e14d..dc2b46236c5cb5cd7ba12ec5fd9f311868978983 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 5d0bb8748dd1df5cd6a262d7e3a925fe4b4b5efd..c2a6e4091357704b5b0cd714304d8bf862462f5d 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 c0a625f290cc7c25f924321a8eb221dd71547429..07df96b43f5962fb67dca3bcd3bd014c268d6029 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 e182e6569bbd138713ec0047de606136254d81c4..3593a1496056d2aa7648142c67bd7952d5b589f6 100644 (file)
@@ -1151,13 +1151,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
                /* Enable VDDC charge pump */
                ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP;
        } else if (vddio >= 3100 && vdda >= 3100) {
-               /*
-                * if vddio and vddd > 3.1v,
-                * charge pump should be clean before set ana_pwr
-                */
-               snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
-                               SGTL5000_VDDC_CHRGPMP_POWERUP, 0);
-
+               ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP;
                /* VDDC use VDDIO rail */
                lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
                lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO <<
index 47b257e4180965f38be5c393cab204945f444b7f..7947c0ebb1ed88a442ecd8e73338fe858c67819c 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 20376d234fb83eb26c3bb5eac6c31bc21d5ab24d..7651fe4e6a458907d468675031b7685be4cdf945 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 3a1343fa109b482860811baea1566d354e574399..007a0e3bc2735c0c6f9d8325f15445657fcfd374 100644 (file)
@@ -106,13 +106,11 @@ static const struct reg_default sta32x_regs[] = {
 };
 
 static const struct regmap_range sta32x_write_regs_range[] = {
-       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
-       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+       regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
 };
 
 static const struct regmap_range sta32x_read_regs_range[] = {
-       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
-       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+       regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
 };
 
 static const struct regmap_range sta32x_volatile_regs_range[] = {
index bda2ee18769ed71e34c96a5a4e93b2621b2dfab2..669e3228241e39d14a2cb009a508cbdb1f6b9fcb 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 ae23acdd2708842b020fca697cdf011d88cff60d..dfb4ff5cc9ea1a697e050cc2d9343dfc9ff58618 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 249ef5c4c762795bfb19f3545ce8398868f4dba3..32942bed34b1e9bb67227adddd5c662b92aa2a9b 100644 (file)
@@ -281,7 +281,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = priv->deemph;
+       ucontrol->value.integer.value[0] = priv->deemph;
 
        return 0;
 }
@@ -292,7 +292,7 @@ static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 
-       priv->deemph = ucontrol->value.enumerated.item[0];
+       priv->deemph = ucontrol->value.integer.value[0];
 
        return tas5086_set_deemph(codec);
 }
index 8d9de49a50524bb4e88ebd62cb580e17239b07d6..21d5402e343fbcdd7a433931bc9a78d0edac45e9 100644 (file)
@@ -610,7 +610,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ucontrol->value.enumerated.item[0] = wm2000->anc_active;
+       ucontrol->value.integer.value[0] = wm2000->anc_active;
 
        return 0;
 }
@@ -620,7 +620,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int anc_active = ucontrol->value.enumerated.item[0];
+       int anc_active = ucontrol->value.integer.value[0];
        int ret;
 
        if (anc_active > 1)
@@ -643,7 +643,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ucontrol->value.enumerated.item[0] = wm2000->spk_ena;
+       ucontrol->value.integer.value[0] = wm2000->spk_ena;
 
        return 0;
 }
@@ -653,7 +653,7 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int val = ucontrol->value.enumerated.item[0];
+       int val = ucontrol->value.integer.value[0];
        int ret;
 
        if (val > 1)
index 6d0fe0ac95a3f6121d87c52cfa4f17f6ec844651..0c6d1bc0526eff324d180f0c3a7041ff3aa5fe00 100644 (file)
@@ -1861,7 +1861,6 @@ static unsigned int wm5102_digital_vu[] = {
        ARIZONA_DAC_DIGITAL_VOLUME_2L,
        ARIZONA_DAC_DIGITAL_VOLUME_2R,
        ARIZONA_DAC_DIGITAL_VOLUME_3L,
-       ARIZONA_DAC_DIGITAL_VOLUME_3R,
        ARIZONA_DAC_DIGITAL_VOLUME_4L,
        ARIZONA_DAC_DIGITAL_VOLUME_4R,
        ARIZONA_DAC_DIGITAL_VOLUME_5L,
index c81a9eab3e3e5113121a9e2c90f1971a410d41fe..c65e5a75fc1afd4e992cca9bda59db14ddba24f1 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 098c143f44d653d99c33f36e02edde9eca6600d8..c6d10533e2bde5170f8ac963333b52c62782c27f 100644 (file)
@@ -125,7 +125,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8731->deemph;
+       ucontrol->value.integer.value[0] = wm8731->deemph;
 
        return 0;
 }
@@ -135,7 +135,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index 31bb4801a00564158fd695dd7aa3438d916c6b97..9e71c768966f050e0a8279b54ec4e9eeb7f8e6d9 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 21ca3a94fc96eadabbc42cfcfdbf8b7eeefb5472..c50a5959345fcf346f55e32056c2b1d4ae5ebd11 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 b2b0e68f707e32037fe8dc623aed5be1b2cda73c..1bd4ace295948a4851132e9f75d3e3c12529ea9c 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 e72d4f4ba6b154f707086363a8f88081cff9636a..a39a2563dc6704e83835a1a2d6bfceeed4f4171f 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 dde462c082be0eb6124e0f881b9a1ed936e34c77..04b04f8e147c6bdeada6decdca981a026ce57afa 100644 (file)
@@ -442,7 +442,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8903->deemph;
+       ucontrol->value.integer.value[0] = wm8903->deemph;
 
        return 0;
 }
@@ -452,7 +452,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index d3b3f57668ccae412f0a75d61f91f9f34f1f0fb0..215e93c1ddf0358f42dc5581fd01b1d9a3d7e1e0 100644 (file)
@@ -525,7 +525,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8904->deemph;
+       ucontrol->value.integer.value[0] = wm8904->deemph;
        return 0;
 }
 
@@ -534,7 +534,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 1ab2d462afadfb24a7205638a779bb0152eb702a..00bec915d6522152a5d40dcc3d2df52ef16424eb 100644 (file)
@@ -393,7 +393,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8955->deemph;
+       ucontrol->value.integer.value[0] = wm8955->deemph;
        return 0;
 }
 
@@ -402,7 +402,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index cf8fecf97f2c7ee06fff2741bea074bd32ceb7fc..3035d98564156746bc4e814f744e1ea0f236564a 100644 (file)
@@ -184,7 +184,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 
-       ucontrol->value.enumerated.item[0] = wm8960->deemph;
+       ucontrol->value.integer.value[0] = wm8960->deemph;
        return 0;
 }
 
@@ -193,7 +193,7 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.enumerated.item[0];
+       int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 39ddb9b8834ccbf19a996605019eb8e74b4dddcf..f9cbabdc623889e1adfa066674bed51a868bd49a 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 9517571e820d9576b9505be863a73f3c02116cb8..98c9525bd751fbacb0eec07f6465869cbc3e2aa5 100644 (file)
@@ -180,7 +180,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val = ucontrol->value.enumerated.item[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
@@ -193,7 +193,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&wm9712->lock);
        old = wm9712->hp_mixer[mixer];
-       if (ucontrol->value.enumerated.item[0])
+       if (ucontrol->value.integer.value[0])
                wm9712->hp_mixer[mixer] |= mask;
        else
                wm9712->hp_mixer[mixer] &= ~mask;
@@ -231,7 +231,7 @@ static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
        mixer = mc->shift >> 8;
        shift = mc->shift & 0xff;
 
-       ucontrol->value.enumerated.item[0] =
+       ucontrol->value.integer.value[0] =
                (wm9712->hp_mixer[mixer] >> shift) & 1;
 
        return 0;
index 68222917b396666b975cc2aa96e13d983bf52fc2..79552953e1bdc607e4d25c95aa5ab473637be6cc 100644 (file)
@@ -255,7 +255,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val = ucontrol->value.enumerated.item[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
@@ -268,7 +268,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&wm9713->lock);
        old = wm9713->hp_mixer[mixer];
-       if (ucontrol->value.enumerated.item[0])
+       if (ucontrol->value.integer.value[0])
                wm9713->hp_mixer[mixer] |= mask;
        else
                wm9713->hp_mixer[mixer] &= ~mask;
@@ -306,7 +306,7 @@ static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
        mixer = mc->shift >> 8;
        shift = mc->shift & 0xff;
 
-       ucontrol->value.enumerated.item[0] =
+       ucontrol->value.integer.value[0] =
                (wm9713->hp_mixer[mixer] >> shift) & 1;
 
        return 0;
index ff67b334065badc1011807648ac671a4d07765bf..d01c2095452f9a0aaa5a2f1e91d2753fd48b1500 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 2b81ca418d2a67d93087e0acd0fc896cb2478210..3736d9aabc563c9b006c9c00a6abea196e3e5daf 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 09bf2ba92d38e3783c8a2b4655c308a54968cc90..f883933c1a194d8a6631b919f91b52cb4c7acf9e 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 b6bb5947a8a8435f5219d4d8efb541e842e531f4..731fb0d86c6ab305a499baaa306112353b02782e 100644 (file)
@@ -117,7 +117,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
-       struct snd_soc_codec *codec = rtd->codec;
        struct device_node *np = card->dev->of_node;
        int ret;
 
@@ -136,9 +135,9 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        /* not connected */
-       snd_soc_dapm_nc_pin(&codec->dapm, "MONO_LOUT");
-       snd_soc_dapm_nc_pin(&codec->dapm, "HPLCOM");
-       snd_soc_dapm_nc_pin(&codec->dapm, "HPRCOM");
+       snd_soc_dapm_nc_pin(&card->dapm, "MONO_LOUT");
+       snd_soc_dapm_nc_pin(&card->dapm, "HPLCOM");
+       snd_soc_dapm_nc_pin(&card->dapm, "HPRCOM");
 
        return 0;
 }
@@ -425,18 +424,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 15fb28fc8e1b0f2a76d8957f9f85952eb5bb8127..56cb4d95637dda5443ae0766192fedb5217af1df 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 de3b155a50116f4e533c8f22e0fc6b933e8040ae..bb4b78eada586df9b210ff03981f44149e85f25c 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
+#include <linux/platform_data/davinci_asp.h>
+#include <linux/math64.h>
 
 #include <sound/asoundef.h>
 #include <sound/core.h>
@@ -36,7 +38,6 @@
 #include <sound/dmaengine_pcm.h>
 #include <sound/omap-pcm.h>
 
-#include "davinci-pcm.h"
 #include "edma-pcm.h"
 #include "davinci-mcasp.h"
 
@@ -62,10 +63,15 @@ struct davinci_mcasp_context {
        u32     config_regs[ARRAY_SIZE(context_regs)];
        u32     afifo_regs[2]; /* for read/write fifo control registers */
        u32     *xrsr_regs; /* for serializer configuration */
+       bool    pm_state;
+};
+
+struct davinci_mcasp_ruledata {
+       struct davinci_mcasp *mcasp;
+       int serializers;
 };
 
 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 +88,7 @@ struct davinci_mcasp {
        u16     bclk_lrclk_ratio;
        int     streams;
        u32     irq_request[2];
+       int     dma_request[2];
 
        int     sysclk_freq;
        bool    bclk_master;
@@ -98,6 +105,8 @@ struct davinci_mcasp {
 #ifdef CONFIG_PM_SLEEP
        struct davinci_mcasp_context context;
 #endif
+
+       struct davinci_mcasp_ruledata ruledata[2];
 };
 
 static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
@@ -441,6 +450,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);
@@ -507,7 +528,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
        }
 out:
-       pm_runtime_put_sync(mcasp->dev);
+       pm_runtime_put(mcasp->dev);
        return ret;
 }
 
@@ -516,6 +537,7 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
+       pm_runtime_get_sync(mcasp->dev);
        switch (div_id) {
        case 0:         /* MCLK divider */
                mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
@@ -541,6 +563,7 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
                return -EINVAL;
        }
 
+       pm_runtime_put(mcasp->dev);
        return 0;
 }
 
@@ -555,6 +578,7 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
+       pm_runtime_get_sync(mcasp->dev);
        if (dir == SND_SOC_CLOCK_OUT) {
                mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
@@ -567,6 +591,7 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
        mcasp->sysclk_freq = freq;
 
+       pm_runtime_put(mcasp->dev);
        return 0;
 }
 
@@ -631,7 +656,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 +723,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 +756,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;
@@ -855,13 +876,35 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
        return 0;
 }
 
+static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
+                                     unsigned int bclk_freq,
+                                     int *error_ppm)
+{
+       int div = mcasp->sysclk_freq / bclk_freq;
+       int rem = mcasp->sysclk_freq % bclk_freq;
+
+       if (rem != 0) {
+               if (div == 0 ||
+                   ((mcasp->sysclk_freq / div) - bclk_freq) >
+                   (bclk_freq - (mcasp->sysclk_freq / (div+1)))) {
+                       div++;
+                       rem = rem - bclk_freq;
+               }
+       }
+       if (error_ppm)
+               *error_ppm =
+                       (div*1000000 + (int)div64_long(1000000LL*rem,
+                                                      (int)bclk_freq))
+                       /div - 1000000;
+
+       return div;
+}
+
 static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params,
                                        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);
@@ -872,16 +915,20 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
         * the machine driver, we need to calculate the ratio.
         */
        if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
-               unsigned int bclk_freq = snd_soc_params_to_bclk(params);
-               unsigned int div = mcasp->sysclk_freq / bclk_freq;
-               if (mcasp->sysclk_freq % bclk_freq != 0) {
-                       if (((mcasp->sysclk_freq / div) - bclk_freq) >
-                           (bclk_freq - (mcasp->sysclk_freq / (div+1))))
-                               div++;
-                       dev_warn(mcasp->dev,
-                                "Inaccurate BCLK: %u Hz / %u != %u Hz\n",
-                                mcasp->sysclk_freq, div, bclk_freq);
-               }
+               int channels = params_channels(params);
+               int rate = params_rate(params);
+               int sbits = params_width(params);
+               int ppm, div;
+
+               if (channels > mcasp->tdm_slots)
+                       channels = mcasp->tdm_slots;
+
+               div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*channels,
+                                                &ppm);
+               if (ppm)
+                       dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
+                                ppm);
+
                __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0);
        }
 
@@ -902,31 +949,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 +977,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)
@@ -973,10 +1010,126 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static const unsigned int davinci_mcasp_dai_rates[] = {
+       8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+       88200, 96000, 176400, 192000,
+};
+
+#define DAVINCI_MAX_RATE_ERROR_PPM 1000
+
+static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
+                                     struct snd_pcm_hw_rule *rule)
+{
+       struct davinci_mcasp_ruledata *rd = rule->private;
+       struct snd_interval *ri =
+               hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       int sbits = params_width(params);
+       int channels = params_channels(params);
+       unsigned int list[ARRAY_SIZE(davinci_mcasp_dai_rates)];
+       int i, count = 0;
+
+       if (channels > rd->mcasp->tdm_slots)
+               channels = rd->mcasp->tdm_slots;
+
+       for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) {
+               if (ri->min <= davinci_mcasp_dai_rates[i] &&
+                   ri->max >= davinci_mcasp_dai_rates[i]) {
+                       uint bclk_freq = sbits*channels*
+                               davinci_mcasp_dai_rates[i];
+                       int ppm;
+
+                       davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
+                       if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM)
+                               list[count++] = davinci_mcasp_dai_rates[i];
+               }
+       }
+       dev_dbg(rd->mcasp->dev,
+               "%d frequencies (%d-%d) for %d sbits and %d channels\n",
+               count, ri->min, ri->max, sbits, channels);
+
+       return snd_interval_list(hw_param_interval(params, rule->var),
+                                count, list, 0);
+}
+
+static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
+                                       struct snd_pcm_hw_rule *rule)
+{
+       struct davinci_mcasp_ruledata *rd = rule->private;
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_mask nfmt;
+       int rate = params_rate(params);
+       int channels = params_channels(params);
+       int i, count = 0;
+
+       snd_mask_none(&nfmt);
+
+       if (channels > rd->mcasp->tdm_slots)
+               channels = rd->mcasp->tdm_slots;
+
+       for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
+               if (snd_mask_test(fmt, i)) {
+                       uint bclk_freq = snd_pcm_format_width(i)*channels*rate;
+                       int ppm;
+
+                       davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
+                       if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
+                               snd_mask_set(&nfmt, i);
+                               count++;
+                       }
+               }
+       }
+       dev_dbg(rd->mcasp->dev,
+               "%d possible sample format for %d Hz and %d channels\n",
+               count, rate, channels);
+
+       return snd_mask_refine(fmt, &nfmt);
+}
+
+static int davinci_mcasp_hw_rule_channels(struct snd_pcm_hw_params *params,
+                                         struct snd_pcm_hw_rule *rule)
+{
+       struct davinci_mcasp_ruledata *rd = rule->private;
+       struct snd_interval *ci =
+               hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       int sbits = params_width(params);
+       int rate = params_rate(params);
+       int max_chan_per_wire = rd->mcasp->tdm_slots < ci->max ?
+               rd->mcasp->tdm_slots : ci->max;
+       unsigned int list[ci->max - ci->min + 1];
+       int c1, c, count = 0;
+
+       for (c1 = ci->min; c1 <= max_chan_per_wire; c1++) {
+               uint bclk_freq = c1*sbits*rate;
+               int ppm;
+
+               davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
+               if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
+                       /* If we can use all tdm_slots, we can put any
+                          amount of channels to remaining wires as
+                          long as they fit in. */
+                       if (c1 == rd->mcasp->tdm_slots) {
+                               for (c = c1; c <= rd->serializers*c1 &&
+                                            c <= ci->max; c++)
+                                       list[count++] = c;
+                       } else {
+                               list[count++] = c1;
+                       }
+               }
+       }
+       dev_dbg(rd->mcasp->dev,
+               "%d possible channel counts (%d-%d) for %d Hz and %d sbits\n",
+               count, ci->min, ci->max, rate, sbits);
+
+       return snd_interval_list(hw_param_interval(params, rule->var),
+                                count, list, 0);
+}
+
 static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *cpu_dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct davinci_mcasp_ruledata *ruledata =
+                                       &mcasp->ruledata[substream->stream];
        u32 max_channels = 0;
        int i, dir;
 
@@ -998,6 +1151,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                if (mcasp->serial_dir[i] == dir)
                        max_channels++;
        }
+       ruledata->serializers = max_channels;
        max_channels *= mcasp->tdm_slots;
        /*
         * If the already active stream has less channels than the calculated
@@ -1012,6 +1166,42 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
        snd_pcm_hw_constraint_minmax(substream->runtime,
                                     SNDRV_PCM_HW_PARAM_CHANNELS,
                                     2, max_channels);
+
+       /*
+        * If we rely on implicit BCLK divider setting we should
+        * set constraints based on what we can provide.
+        */
+       if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
+               int ret;
+
+               ruledata->mcasp = mcasp;
+
+               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_RATE,
+                                         davinci_mcasp_hw_rule_rate,
+                                         ruledata,
+                                         SNDRV_PCM_HW_PARAM_FORMAT,
+                                         SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+               if (ret)
+                       return ret;
+               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_FORMAT,
+                                         davinci_mcasp_hw_rule_format,
+                                         ruledata,
+                                         SNDRV_PCM_HW_PARAM_RATE,
+                                         SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+               if (ret)
+                       return ret;
+               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_CHANNELS,
+                                         davinci_mcasp_hw_rule_channels,
+                                         ruledata,
+                                         SNDRV_PCM_HW_PARAM_RATE,
+                                         SNDRV_PCM_HW_PARAM_FORMAT, -1);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -1043,17 +1233,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;
 }
@@ -1066,6 +1247,10 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
        u32 reg;
        int i;
 
+       context->pm_state = pm_runtime_enabled(mcasp->dev);
+       if (!context->pm_state)
+               pm_runtime_get_sync(mcasp->dev);
+
        for (i = 0; i < ARRAY_SIZE(context_regs); i++)
                context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
 
@@ -1082,6 +1267,8 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
                context->xrsr_regs[i] = mcasp_get_reg(mcasp,
                                                DAVINCI_MCASP_XRSRCTL_REG(i));
 
+       pm_runtime_put_sync(mcasp->dev);
+
        return 0;
 }
 
@@ -1092,6 +1279,8 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai)
        u32 reg;
        int i;
 
+       pm_runtime_get_sync(mcasp->dev);
+
        for (i = 0; i < ARRAY_SIZE(context_regs); i++)
                mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
 
@@ -1108,6 +1297,9 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai)
                mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
                              context->xrsr_regs[i]);
 
+       if (!context->pm_state)
+               pm_runtime_put_sync(mcasp->dev);
+
        return 0;
 }
 #else
@@ -1172,28 +1364,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 +1558,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;
 
@@ -1415,13 +1603,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       ret = pm_runtime_get_sync(&pdev->dev);
-       if (IS_ERR_VALUE(ret)) {
-               dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
-               pm_runtime_disable(&pdev->dev);
-               return ret;
-       }
-
        mcasp->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
        if (!mcasp->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
@@ -1509,59 +1690,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 +1751,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;
@@ -1621,14 +1782,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        return 0;
 
 err:
-       pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return ret;
 }
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
-       pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
        return 0;
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 5bee04279ebede35dde51844be4c383862e914eb..fabd05f24aebe9b288735177fce0f5e3a250751c 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 081e406b3713aae2509206e9a779325eb7ec263e..19c302b0d763976fba1bc79b927f8b39e03dfc83 100644 (file)
@@ -24,7 +24,7 @@ config SND_SOC_FSL_SAI
          in-tree drivers select it automatically.
 
 config SND_SOC_FSL_SSI
-       tristate "Synchronous Serial Interface module support"
+       tristate "Synchronous Serial Interface module (SSI) support"
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
        select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC)
        select REGMAP_MMIO
@@ -35,7 +35,7 @@ config SND_SOC_FSL_SSI
          in-tree drivers select it automatically.
 
 config SND_SOC_FSL_SPDIF
-       tristate "Sony/Philips Digital Interface module support"
+       tristate "Sony/Philips Digital Interface (S/PDIF) module support"
        select REGMAP_MMIO
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
        select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC)
index 3f6959c8e2f71b44cf054445b85553960e8c94d9..de438871040bd43f8b1e6a05e4a479261e5ea4bd 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 75870c0ea2c9f613d9b4ebe3e10efd53430e5363..91eb3aef7f02f84d4dd2ec92cb46a9ce2ad67e55 100644 (file)
@@ -1049,7 +1049,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
                                enum spdif_txrate index, bool round)
 {
        const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
-       bool is_sysclk = clk == spdif_priv->sysclk;
+       bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
        u64 rate_ideal, rate_actual, sub;
        u32 sysclk_dfmin, sysclk_dfmax;
        u32 txclk_df, sysclk_df, arate;
@@ -1143,7 +1143,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
                        spdif_priv->txclk_src[index], rate[index]);
        dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n",
                        spdif_priv->txclk_df[index], rate[index]);
-       if (spdif_priv->txclk[index] == spdif_priv->sysclk)
+       if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk))
                dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n",
                                spdif_priv->sysclk_df[index], rate[index]);
        dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n",
index 2595611e8a6ded3876345767bde2ce51e079c9ee..e8bb8eef1d16bee3d9d8ca5e4b7e4d5a7a026267 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
@@ -1285,7 +1288,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        const struct of_device_id *of_id;
        const char *p, *sprop;
        const uint32_t *iprop;
-       struct resource res;
+       struct resource *res;
        void __iomem *iomem;
        char name[64];
 
@@ -1332,19 +1335,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
        ssi_private->cpu_dai_drv.name = dev_name(&pdev->dev);
 
-       /* Get the addresses and IRQ */
-       ret = of_address_to_resource(np, 0, &res);
-       if (ret) {
-               dev_err(&pdev->dev, "could not determine device resources\n");
-               return ret;
-       }
-       ssi_private->ssi_phys = res.start;
-
-       iomem = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
-       if (!iomem) {
-               dev_err(&pdev->dev, "could not map device resources\n");
-               return -ENOMEM;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       iomem = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(iomem))
+               return PTR_ERR(iomem);
+       ssi_private->ssi_phys = res->start;
 
        ret = of_property_match_string(np, "clock-names", "ipg");
        if (ret < 0) {
@@ -1390,8 +1385,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
-                                        &ssi_private->cpu_dai_drv, 1);
+       ret = devm_snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
+                                             &ssi_private->cpu_dai_drv, 1);
        if (ret) {
                dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
                goto error_asoc_register;
@@ -1404,13 +1399,13 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                if (ret < 0) {
                        dev_err(&pdev->dev, "could not claim irq %u\n",
                                        ssi_private->irq);
-                       goto error_irq;
+                       goto error_asoc_register;
                }
        }
 
        ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev);
        if (ret)
-               goto error_irq;
+               goto error_asoc_register;
 
        /*
         * If codec-handle property is missing from SSI node, we assume
@@ -1451,9 +1446,6 @@ done:
 error_sound_card:
        fsl_ssi_debugfs_remove(&ssi_private->dbg_stats);
 
-error_irq:
-       snd_soc_unregister_component(&pdev->dev);
-
 error_asoc_register:
        if (ssi_private->soc->imx)
                fsl_ssi_imx_clean(pdev, ssi_private);
@@ -1469,7 +1461,6 @@ static int fsl_ssi_remove(struct platform_device *pdev)
 
        if (ssi_private->pdev)
                platform_device_unregister(ssi_private->pdev);
-       snd_soc_unregister_component(&pdev->dev);
 
        if (ssi_private->soc->imx)
                fsl_ssi_imx_clean(pdev, ssi_private);
index f8cf10e16ce9c7ef0d192668894354dae320b840..20e7400e2611e41ef057d9b2e22413a7c6a73c98 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 08d2a8069b0abd584d668af96663f689514b4a14..0bab76051fd830dd0bc0a3d993341ad8cd759afe 100644 (file)
@@ -326,7 +326,7 @@ static int psc_ac97_of_remove(struct platform_device *op)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id psc_ac97_match[] = {
+static const struct of_device_id psc_ac97_match[] = {
        { .compatible = "fsl,mpc5200-psc-ac97", },
        { .compatible = "fsl,mpc5200b-psc-ac97", },
        {}
index 51fb0c00fe737d757da59a594ee3f125f776a022..d8232943ccb67c42471959d0cb6f4cd2e36114d9 100644 (file)
@@ -217,7 +217,7 @@ static int psc_i2s_of_remove(struct platform_device *op)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id psc_i2s_match[] = {
+static const struct of_device_id psc_i2s_match[] = {
        { .compatible = "fsl,mpc5200-psc-i2s", },
        { .compatible = "fsl,mpc5200b-psc-i2s", },
        {}
index c44459d24c50502d12c5ec1e9de86539139a0d3d..ec731223cab3d7bfbfe8208571a9c67e59276d3a 100644 (file)
@@ -113,7 +113,7 @@ static int pcm030_fabric_remove(struct platform_device *op)
        return ret;
 }
 
-static struct of_device_id pcm030_audio_match[] = {
+static const struct of_device_id pcm030_audio_match[] = {
        { .compatible = "phytec,pcm030-audio-fabric", },
        {}
 };
index a958937ab405ce0d79e43942942c875ad69f66da..b454972dce3521a48cb0762651bc3fad0a234690 100644 (file)
@@ -202,23 +202,20 @@ static struct snd_soc_jack_pin mic_jack_pins[] = {
 static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       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);
 
-       snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+       snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");
 
        return 0;
 }
index f7c6734bd5daee1dafd76ba8b6feafa05b2a6c52..c49a408fc7a6a267e4a9d106d1019547b558c3ed 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 a8e53c45c6b655953ef93034bbc238707611b313..cd9aee9871a36a4400646441f1105d949fe5a2af 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 07f77815a586fea295cf40f14a66f4c2cdedf73c..b05fb1c1a8483e18ea7e5226325563ea82d044c0 100644 (file)
 
 #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
 #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
+#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24
+#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16
+#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_MASK \
+                       (0xf << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET)
+#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_MASK \
+                       (0x1f <<  JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET)
 
 #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
 #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
@@ -79,6 +85,7 @@
 #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET  16
 
 #define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
+#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13)
 #define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
 #define JZ_AIC_I2S_FMT_MSB BIT(0)
 
 #define JZ_AIC_CLK_DIV_MASK 0xf
 #define I2SDIV_DV_SHIFT 8
 #define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
+#define I2SDIV_IDV_SHIFT 8
+#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT)
+
+enum jz47xx_i2s_version {
+       JZ_I2S_JZ4740,
+       JZ_I2S_JZ4780,
+};
 
 struct jz4740_i2s {
        struct resource *mem;
@@ -98,6 +112,8 @@ struct jz4740_i2s {
 
        struct snd_dmaengine_dai_dma_data playback_dma_data;
        struct snd_dmaengine_dai_dma_data capture_dma_data;
+
+       enum jz47xx_i2s_version version;
 };
 
 static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
@@ -267,13 +283,22 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
                        ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
                else
                        ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
+
+               div_reg &= ~I2SDIV_DV_MASK;
+               div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
        } else {
                ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
                ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
+
+               if (i2s->version >= JZ_I2S_JZ4780) {
+                       div_reg &= ~I2SDIV_IDV_MASK;
+                       div_reg |= (div - 1) << I2SDIV_IDV_SHIFT;
+               } else {
+                       div_reg &= ~I2SDIV_DV_MASK;
+                       div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
+               }
        }
 
-       div_reg &= ~I2SDIV_DV_MASK;
-       div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
        jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg);
 
@@ -369,11 +394,19 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
        snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
                &i2s->capture_dma_data);
 
-       conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
-               (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
-               JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
-               JZ_AIC_CONF_I2S |
-               JZ_AIC_CONF_INTERNAL_CODEC;
+       if (i2s->version >= JZ_I2S_JZ4780) {
+               conf = (7 << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
+                       (8 << JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
+                       JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
+                       JZ_AIC_CONF_I2S |
+                       JZ_AIC_CONF_INTERNAL_CODEC;
+       } else {
+               conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
+                       (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
+                       JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
+                       JZ_AIC_CONF_I2S |
+                       JZ_AIC_CONF_INTERNAL_CODEC;
+       }
 
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
@@ -422,13 +455,34 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
        .resume = jz4740_i2s_resume,
 };
 
+static struct snd_soc_dai_driver jz4780_i2s_dai = {
+       .probe = jz4740_i2s_dai_probe,
+       .remove = jz4740_i2s_dai_remove,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = JZ4740_I2S_FMTS,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = JZ4740_I2S_FMTS,
+       },
+       .ops = &jz4740_i2s_dai_ops,
+       .suspend = jz4740_i2s_suspend,
+       .resume = jz4740_i2s_resume,
+};
+
 static const struct snd_soc_component_driver jz4740_i2s_component = {
        .name           = "jz4740-i2s",
 };
 
 #ifdef CONFIG_OF
 static const struct of_device_id jz4740_of_matches[] = {
-       { .compatible = "ingenic,jz4740-i2s" },
+       { .compatible = "ingenic,jz4740-i2s", .data = (void *)JZ_I2S_JZ4740 },
+       { .compatible = "ingenic,jz4780-i2s", .data = (void *)JZ_I2S_JZ4780 },
        { /* sentinel */ }
 };
 #endif
@@ -438,11 +492,16 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
        struct jz4740_i2s *i2s;
        struct resource *mem;
        int ret;
+       const struct of_device_id *match;
 
        i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
        if (!i2s)
                return -ENOMEM;
 
+       match = of_match_device(jz4740_of_matches, &pdev->dev);
+       if (match)
+               i2s->version = (enum jz47xx_i2s_version)match->data;
+
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        i2s->base = devm_ioremap_resource(&pdev->dev, mem);
        if (IS_ERR(i2s->base))
@@ -460,8 +519,13 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, i2s);
 
-       ret = devm_snd_soc_register_component(&pdev->dev,
-               &jz4740_i2s_component, &jz4740_i2s_dai, 1);
+       if (i2s->version == JZ_I2S_JZ4780)
+               ret = devm_snd_soc_register_component(&pdev->dev,
+                       &jz4740_i2s_component, &jz4780_i2s_dai, 1);
+       else
+               ret = devm_snd_soc_register_component(&pdev->dev,
+                       &jz4740_i2s_component, &jz4740_i2s_dai, 1);
+
        if (ret)
                return ret;
 
index def7d8260c4e579c06eeba8ba45f422e1fb482c5..3a36d60e178504637963a3193f2a60514e0d272f 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 {
@@ -643,7 +643,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_OF
-static struct of_device_id mvebu_audio_of_match[] = {
+static const struct of_device_id mvebu_audio_of_match[] = {
        { .compatible = "marvell,kirkwood-audio" },
        { .compatible = "marvell,dove-audio" },
        { .compatible = "marvell,armada370-audio" },
index 59f7e8ed1a6898937e3472016bce5e4bdc11e3de..d0b725705914a1e8935a1276250193c8439a60d9 100644 (file)
 struct nuc900_audio {
        void __iomem *mmio;
        spinlock_t lock;
-       dma_addr_t dma_addr[2];
-       unsigned long buffersize[2];
        unsigned long irq_num;
-       struct snd_pcm_substream *substream;
        struct resource *res;
        struct clk *clk;
        struct device *dev;
index b809fa909e4d6d6f91a78bdf5e9cda0e7f9c2fa8..5ae5ca15b6d6bf109b20a236f69f1b6a2900bd7a 100644 (file)
@@ -42,29 +42,10 @@ static const struct snd_pcm_hardware nuc900_pcm_hardware = {
 static int nuc900_dma_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct nuc900_audio *nuc900_audio = runtime->private_data;
-       unsigned long flags;
-       int ret = 0;
-
-       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-       if (ret < 0)
-               return ret;
-
-       spin_lock_irqsave(&nuc900_audio->lock, flags);
-
-       nuc900_audio->substream = substream;
-       nuc900_audio->dma_addr[substream->stream] = runtime->dma_addr;
-       nuc900_audio->buffersize[substream->stream] =
-                                               params_buffer_bytes(params);
-
-       spin_unlock_irqrestore(&nuc900_audio->lock, flags);
-
-       return ret;
+       return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 }
 
-static void nuc900_update_dma_register(struct snd_pcm_substream *substream,
-                               dma_addr_t dma_addr, size_t count)
+static void nuc900_update_dma_register(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct nuc900_audio *nuc900_audio = runtime->private_data;
@@ -78,8 +59,8 @@ static void nuc900_update_dma_register(struct snd_pcm_substream *substream,
                mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH;
        }
 
-       AUDIO_WRITE(mmio_addr, dma_addr);
-       AUDIO_WRITE(mmio_len, count);
+       AUDIO_WRITE(mmio_addr, runtime->dma_addr);
+       AUDIO_WRITE(mmio_len, runtime->dma_bytes);
 }
 
 static void nuc900_dma_start(struct snd_pcm_substream *substream)
@@ -170,9 +151,7 @@ static int nuc900_dma_prepare(struct snd_pcm_substream *substream)
 
        spin_lock_irqsave(&nuc900_audio->lock, flags);
 
-       nuc900_update_dma_register(substream,
-                               nuc900_audio->dma_addr[substream->stream],
-                               nuc900_audio->buffersize[substream->stream]);
+       nuc900_update_dma_register(substream);
 
        val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
 
index a2cd3486ac554aceb9aeb75ed03314c4d30814fd..e7c78b0406b59c62fef534849571e49ed7b643d0 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 706613077c155e93d7952aab02c49ccfccafaecc..16cc95fa45731b3f9ed6f47896b95b0eadf3a025 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 b9c65f1ad5a85ee9616704e0502bafc37e60a410..0843a68f277c2cffb0bdffa9a5a200b86544950f 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 ccfb41c22e53b11cedbf5d8272a56a757ad283d1..f7eb42aa3f3893ca7cfd76fd2f8a96ff986d68b2 100644 (file)
@@ -352,6 +352,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
                return ret;
 
        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
        card->name = devm_kasprintf(dev, GFP_KERNEL,
                                    "HDMI %s", dev_name(ad->dssdev));
        card->owner = THIS_MODULE;
index c7eb9dd67f608c47ffa93a97c1824e3dae3c867b..fd99d89de6a854606357b50c44deeb43bcfb04ab 100644 (file)
@@ -530,8 +530,19 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 
        case OMAP_MCBSP_SYSCLK_CLKX_EXT:
                regs->srgr2     |= CLKSM;
+               regs->pcr0      |= SCLKME;
+               /*
+                * If McBSP is master but yet the CLKX/CLKR pin drives the SRG,
+                * disable output on those pins. This enables to inject the
+                * reference clock through CLKX/CLKR. For this to work
+                * set_dai_sysclk() _needs_ to be called after set_dai_fmt().
+                */
+               regs->pcr0      &= ~CLKXM;
+               break;
        case OMAP_MCBSP_SYSCLK_CLKR_EXT:
                regs->pcr0      |= SCLKME;
+               /* Disable ouput on CLKR pin in master mode */
+               regs->pcr0      &= ~CLKRM;
                break;
        default:
                err = -ENODEV;
index f4b05bc23e4bfb4d27adf8dea4702539c2696609..6bb623a2a4dfcfa3cda744ca8bef18575baec2d9 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 fb1f6bb87cd430d816e250a2b5d7317c4744c6a7..3673ada43bfb244fd7a17f90e7bc420e7e020ed1 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 7f299357c2d207c457cb9918a5b0a9cc618a3253..c2ddf0fbfa2895732a37d82d19b60c75408d67a7 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 73eb5ddf9753beb405b7d64fae88ede40d57bab2..9f8be7cd567e48c83218624ddfe2cad538ef28d7 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 910336c5ebebd1486048552af7f598b6d7747b0d..c20bbc042425dacb2a478d247f9087b87ba8469c 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 5001dbb9b257764d9b88427de5bc86bebfba5a7b..1753c7d9e760e4bfa14e5b5ed8844b530e7413cf 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 76ccb172d0a77ed23be7b1fc441e388ce41b57fe..bcbfbe8303f7a03ac070c343e19e05d7847f8d8a 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 3cebf6ca03dfb91891cd6e6d5eb51649b504c0b1..0632a36852c8476416f8fcb78d625abb98d658cf 100644 (file)
@@ -174,7 +174,7 @@ config SND_SOC_SMDK_WM8994_PCM
 
 config SND_SOC_SPEYSIDE
        tristate "Audio support for Wolfson Speyside"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C && SPI_MASTER
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8996
        select SND_SOC_WM9081
@@ -189,7 +189,7 @@ config SND_SOC_TOBERMORY
 
 config SND_SOC_BELLS
        tristate "Audio support for Wolfson Bells"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA && I2C && SPI_MASTER
        select SND_SAMSUNG_I2S
        select SND_SOC_WM5102
        select SND_SOC_WM5110
@@ -206,7 +206,7 @@ config SND_SOC_LOWLAND
 
 config SND_SOC_LITTLEMILL
        tristate "Audio support for Wolfson Littlemill"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C
        select SND_SAMSUNG_I2S
        select MFD_WM8994
        select SND_SOC_WM8994
@@ -223,7 +223,7 @@ config SND_SOC_SNOW
 
 config SND_SOC_ODROIDX2
        tristate "Audio support for Odroid-X2 and Odroid-U3"
-       depends on SND_SOC_SAMSUNG
+       depends on SND_SOC_SAMSUNG && I2C
        select SND_SOC_MAX98090
        select SND_SAMSUNG_I2S
        help
@@ -231,6 +231,6 @@ config SND_SOC_ODROIDX2
 
 config SND_SOC_ARNDALE_RT5631_ALC5631
         tristate "Audio support for RT5631(ALC5631) on Arndale Board"
-        depends on SND_SOC_SAMSUNG
+        depends on SND_SOC_SAMSUNG && I2C
         select SND_SAMSUNG_I2S
         select SND_SOC_RT5631
index 59b044255b781c68c733f30f397ff266059ac507..c72e9fb26658ce17036761164e6fd9e083618841 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 141519c21e21d7cbd425cb7b9a6d306278cabdf0..31a820eb0ac37b52992cbc986a17ce11d3c42ca1 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 243dea7ba38f81c7890ebea9af815cc80664111f..5f156093101e3ab2df8290841a656ab062ccd5af 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 873f2cb4bebe3e449d6d32821da672e0916626f0..35e37c457f1fd311ee982169010df6507939924d 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 8291d2a5f1525957b6c4e021c8657d4590ce649e..dfbe2db1c4078da9de1d82d58d95573866cfe73e 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 5ec7c52282f201ba0b8bae03e26e936b6fb142b0..2dcb988bdff21272ffed15c7073e7f4643bee70f 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 9c80506527c4f3c87620fd48235f9e6f3e737834..85ccfb7188cb2d4b36101f14d0fa3dc024436f6f 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 b87b22e88e43decf2d8e66c84ce411f2c97224fa..0c2af21b0b82513176ac841ae8e394cd6711eead 100644 (file)
@@ -1876,7 +1876,40 @@ static void fsi_handler_init(struct fsi_priv *fsi,
        }
 }
 
-static struct of_device_id fsi_of_match[];
+static const struct fsi_core fsi1_core = {
+       .ver    = 1,
+
+       /* Interrupt */
+       .int_st = INT_ST,
+       .iemsk  = IEMSK,
+       .imsk   = IMSK,
+};
+
+static const struct fsi_core fsi2_core = {
+       .ver    = 2,
+
+       /* Interrupt */
+       .int_st = CPU_INT_ST,
+       .iemsk  = CPU_IEMSK,
+       .imsk   = CPU_IMSK,
+       .a_mclk = A_MST_CTLR,
+       .b_mclk = B_MST_CTLR,
+};
+
+static const struct of_device_id fsi_of_match[] = {
+       { .compatible = "renesas,sh_fsi",       .data = &fsi1_core},
+       { .compatible = "renesas,sh_fsi2",      .data = &fsi2_core},
+       {},
+};
+MODULE_DEVICE_TABLE(of, fsi_of_match);
+
+static const struct platform_device_id fsi_id_table[] = {
+       { "sh_fsi",     (kernel_ulong_t)&fsi1_core },
+       { "sh_fsi2",    (kernel_ulong_t)&fsi2_core },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, fsi_id_table);
+
 static int fsi_probe(struct platform_device *pdev)
 {
        struct fsi_master *master;
@@ -2072,40 +2105,6 @@ static struct dev_pm_ops fsi_pm_ops = {
        .resume                 = fsi_resume,
 };
 
-static struct fsi_core fsi1_core = {
-       .ver    = 1,
-
-       /* Interrupt */
-       .int_st = INT_ST,
-       .iemsk  = IEMSK,
-       .imsk   = IMSK,
-};
-
-static struct fsi_core fsi2_core = {
-       .ver    = 2,
-
-       /* Interrupt */
-       .int_st = CPU_INT_ST,
-       .iemsk  = CPU_IEMSK,
-       .imsk   = CPU_IMSK,
-       .a_mclk = A_MST_CTLR,
-       .b_mclk = B_MST_CTLR,
-};
-
-static struct of_device_id fsi_of_match[] = {
-       { .compatible = "renesas,sh_fsi",       .data = &fsi1_core},
-       { .compatible = "renesas,sh_fsi2",      .data = &fsi2_core},
-       {},
-};
-MODULE_DEVICE_TABLE(of, fsi_of_match);
-
-static struct platform_device_id fsi_id_table[] = {
-       { "sh_fsi",     (kernel_ulong_t)&fsi1_core },
-       { "sh_fsi2",    (kernel_ulong_t)&fsi2_core },
-       {},
-};
-MODULE_DEVICE_TABLE(platform, fsi_id_table);
-
 static struct platform_driver fsi_driver = {
        .driver         = {
                .name   = "fsi-pcm-audio",
@@ -2119,7 +2118,7 @@ static struct platform_driver fsi_driver = {
 
 module_platform_driver(fsi_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("SuperH onchip FSI audio driver");
 MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
 MODULE_ALIAS("platform:fsi-pcm-audio");
index 1b53605f7154394d1746cb0a692953e296848c2a..31202e95be1ee6dc5fde83e44ce955347bc8109c 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 d7f9ed959c4e208a8126174f76daee5a79af133f..261997a3f5899d0b3ed357211181eeb00bf7310c 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 e7914bd610e2120644f616e6500bdf3ad9ec24d3..1bccc5515b5a9bbbb2e7c57255aa6a9707b11593 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 81c182b4bad531c8afe3a071da4c9ad41c4d868f..c77d059edc84ce0b63dbd2e82414864d91edf956 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 9e7b627c08e2256dbe09acd063432b7b3b7c1107..f7cb1fd635a0eb32e9e17f82e411356fea3532d7 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 30579ca5bacb985c7dfa9b9ad30f58cee45d6e1a..12b7ff2426da8867177369a4fd603e322b48baca 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)
@@ -1245,7 +1298,8 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
        capture_w = cpu_dai->capture_widget;
        if (play_w && capture_w) {
                ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                          capture_w, play_w);
+                                          dai_link->num_params, capture_w,
+                                          play_w);
                if (ret != 0) {
                        dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
                                play_w->name, capture_w->name, ret);
@@ -1257,7 +1311,8 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
        capture_w = codec_dai->capture_widget;
        if (play_w && capture_w) {
                ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                          capture_w, play_w);
+                                          dai_link->num_params, capture_w,
+                                          play_w);
                if (ret != 0) {
                        dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
                                play_w->name, capture_w->name, ret);
@@ -1306,21 +1361,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 +1461,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 +1558,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 +1594,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 +1614,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 +1673,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 +1717,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 +1732,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 +2411,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 +2441,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 +2769,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 +2816,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 +2934,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 +3146,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 +3279,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 +3364,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 +3624,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 +3634,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 b6f88202b8c99a41c3e941bb8a8a2603e45985a8..defe0f0082b5e8877d6ae092d53395c6387fbaff 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;
@@ -853,6 +843,36 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
        return 0;
 }
 
+/* create new dapm dai link control */
+static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
+{
+       int i, ret;
+       struct snd_kcontrol *kcontrol;
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_card *card = dapm->card->snd_card;
+
+       /* create control for links with > 1 config */
+       if (w->num_params <= 1)
+               return 0;
+
+       /* add kcontrol */
+       for (i = 0; i < w->num_kcontrols; i++) {
+               kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
+                                       w->name, NULL);
+               ret = snd_ctl_add(card, kcontrol);
+               if (ret < 0) {
+                       dev_err(dapm->dev,
+                               "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
+                               w->name, w->kcontrol_news[i].name, ret);
+                       return ret;
+               }
+               kcontrol->private_data = w;
+               w->kcontrols[i] = kcontrol;
+       }
+
+       return 0;
+}
+
 /* We implement power down on suspend by checking the power state of
  * the ALSA card - when we are suspending the ALSA state for the card
  * is set to D3.
@@ -1898,6 +1918,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) {
@@ -2719,6 +2742,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
                case snd_soc_dapm_out_drv:
                        dapm_new_pga(w);
                        break;
+               case snd_soc_dapm_dai_link:
+                       dapm_new_dai_link(w);
+                       break;
                default:
                        break;
                }
@@ -3193,7 +3219,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_dapm_path *source_p, *sink_p;
        struct snd_soc_dai *source, *sink;
-       const struct snd_soc_pcm_stream *config = w->params;
+       const struct snd_soc_pcm_stream *config = w->params + w->params_select;
        struct snd_pcm_substream substream;
        struct snd_pcm_hw_params *params = NULL;
        u64 fmt;
@@ -3285,22 +3311,97 @@ out:
        return ret;
 }
 
+static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = w->params_select;
+
+       return 0;
+}
+
+static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+
+       /* Can't change the config when widget is already powered */
+       if (w->power)
+               return -EBUSY;
+
+       if (ucontrol->value.integer.value[0] == w->params_select)
+               return 0;
+
+       if (ucontrol->value.integer.value[0] >= w->num_params)
+               return -EINVAL;
+
+       w->params_select = ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
 int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
                         const struct snd_soc_pcm_stream *params,
+                        unsigned int num_params,
                         struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
        struct snd_soc_dapm_widget template;
        struct snd_soc_dapm_widget *w;
-       size_t len;
        char *link_name;
-       int ret;
-
-       len = strlen(source->name) + strlen(sink->name) + 2;
-       link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
-       if (!link_name)
+       int ret, count;
+       unsigned long private_value;
+       const char **w_param_text;
+       struct soc_enum w_param_enum[] = {
+               SOC_ENUM_SINGLE(0, 0, 0, NULL),
+       };
+       struct snd_kcontrol_new kcontrol_dai_link[] = {
+               SOC_ENUM_EXT(NULL, w_param_enum[0],
+                            snd_soc_dapm_dai_link_get,
+                            snd_soc_dapm_dai_link_put),
+       };
+       const struct snd_soc_pcm_stream *config = params;
+
+       w_param_text = devm_kcalloc(card->dev, num_params,
+                                       sizeof(char *), GFP_KERNEL);
+       if (!w_param_text)
                return -ENOMEM;
-       snprintf(link_name, len, "%s-%s", source->name, sink->name);
+
+       link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
+                                  source->name, sink->name);
+       if (!link_name) {
+               ret = -ENOMEM;
+               goto outfree_w_param;
+       }
+
+       for (count = 0 ; count < num_params; count++) {
+               if (!config->stream_name) {
+                       dev_warn(card->dapm.dev,
+                               "ASoC: anonymous config %d for dai link %s\n",
+                               count, link_name);
+                       w_param_text[count] =
+                               devm_kasprintf(card->dev, GFP_KERNEL,
+                                              "Anonymous Configuration %d",
+                                              count);
+                       if (!w_param_text[count]) {
+                               ret = -ENOMEM;
+                               goto outfree_link_name;
+                       }
+               } else {
+                       w_param_text[count] = devm_kmemdup(card->dev,
+                                               config->stream_name,
+                                               strlen(config->stream_name) + 1,
+                                               GFP_KERNEL);
+                       if (!w_param_text[count]) {
+                               ret = -ENOMEM;
+                               goto outfree_link_name;
+                       }
+               }
+               config++;
+       }
+       w_param_enum[0].items = num_params;
+       w_param_enum[0].texts = w_param_text;
 
        memset(&template, 0, sizeof(template));
        template.reg = SND_SOC_NOPM;
@@ -3309,6 +3410,30 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
        template.event = snd_soc_dai_link_event;
        template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
                SND_SOC_DAPM_PRE_PMD;
+       template.num_kcontrols = 1;
+       /* duplicate w_param_enum on heap so that memory persists */
+       private_value =
+               (unsigned long) devm_kmemdup(card->dev,
+                       (void *)(kcontrol_dai_link[0].private_value),
+                       sizeof(struct soc_enum), GFP_KERNEL);
+       if (!private_value) {
+               dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
+                       link_name);
+               ret = -ENOMEM;
+               goto outfree_link_name;
+       }
+       kcontrol_dai_link[0].private_value = private_value;
+       /* duplicate kcontrol_dai_link on heap so that memory persists */
+       template.kcontrol_news =
+                               devm_kmemdup(card->dev, &kcontrol_dai_link[0],
+                                       sizeof(struct snd_kcontrol_new),
+                                       GFP_KERNEL);
+       if (!template.kcontrol_news) {
+               dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
+                       link_name);
+               ret = -ENOMEM;
+               goto outfree_private_value;
+       }
 
        dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
 
@@ -3316,15 +3441,32 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
        if (!w) {
                dev_err(card->dev, "ASoC: Failed to create %s widget\n",
                        link_name);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto outfree_kcontrol_news;
        }
 
        w->params = params;
+       w->num_params = num_params;
 
        ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
        if (ret)
-               return ret;
+               goto outfree_w;
        return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
+
+outfree_w:
+       devm_kfree(card->dev, w);
+outfree_kcontrol_news:
+       devm_kfree(card->dev, (void *)template.kcontrol_news);
+outfree_private_value:
+       devm_kfree(card->dev, (void *)private_value);
+outfree_link_name:
+       devm_kfree(card->dev, link_name);
+outfree_w_param:
+       for (count = 0 ; count < num_params; count++)
+               devm_kfree(card->dev, (void *)w_param_text[count]);
+       devm_kfree(card->dev, w_param_text);
+
+       return ret;
 }
 
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
index 4380dcc064a5301a9fa4a077566d6bc450b1d28f..9f60c25c4568e7e1280e1ca28058c48c0ca65efa 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 6b0136e7cb88c2cebd96b12a6a85dc200f9838d3..35fe58f4fa86240b176db74c1789065c62bd17a7 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 769aca2fc5f5af214fcd3505103e714e71531c7b..6dcd06a966c7c6149b8020f806e3bbb9c09af976 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 af3fb997b75228927f4a32b53d65eb78938efd22..902da36581d1ba8af25494b8e69a2fec4415b1eb 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 ed759a3076b8b56063040c4c5f55bcdebff8bf05..773daecaa5e89f04700fafc049d922e37a1f35b7 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 e4cf978a6e3a9a194ef27a5abd62e2e2b67d2bf3..68d8b67e79c1528820fb5aa2801909e7e2aab289 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 e52420dae2b4b02df762df096ba366ad1c621d02..4a95b70f0cf082d6e65efdfca1e8608982037716 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 05dee690f4876167ace542fe500bb077bec26762..97ed593f6010f6dccf4e5eb5db39e4a2381a7692 100644 (file)
@@ -39,7 +39,7 @@ static void change_volume(struct urb *urb_out, int volume[],
                for (; p < buf_end; ++p) {
                        short pv = le16_to_cpu(*p);
                        int val = (pv * volume[chn & 1]) >> 8;
-                       pv = clamp(val, 0x7fff, -0x8000);
+                       pv = clamp(val, -0x8000, 0x7fff);
                        *p = cpu_to_le16(pv);
                        ++chn;
                }
@@ -54,7 +54,7 @@ static void change_volume(struct urb *urb_out, int volume[],
 
                        val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
                        val = (val * volume[chn & 1]) >> 8;
-                       val = clamp(val, 0x7fffff, -0x800000);
+                       val = clamp(val, -0x800000, 0x7fffff);
                        p[0] = val;
                        p[1] = val >> 8;
                        p[2] = val >> 16;
@@ -126,7 +126,7 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
                        short pov = le16_to_cpu(*po);
                        short piv = le16_to_cpu(*pi);
                        int val = pov + ((piv * volume) >> 8);
-                       pov = clamp(val, 0x7fff, -0x8000);
+                       pov = clamp(val, -0x8000, 0x7fff);
                        *po = cpu_to_le16(pov);
                }
        }
index 67d476548dcf9094acd61e0ff74f0f320af1556a..07f984d5f5162809ee6124f651585df5c3a4496f 100644 (file)
@@ -1773,6 +1773,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x0582, 0x0159),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "UA-22", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 /* this catches most recent vendor-specific Roland devices */
 {
        .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
index 6c14afe8c1b18ea1ab4a50aa4b6dc46925d304a1..db1d3a29d97fec67c47a4dd84eca2f7779ec1865 100644 (file)
@@ -289,7 +289,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault)
        memcpy_t fn = r->fn.memcpy;
        int i;
 
-       memcpy_alloc_mem(&src, &dst, len);
+       memcpy_alloc_mem(&dst, &src, len);
 
        if (prefault)
                fn(dst, src, len);
@@ -312,7 +312,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len,
        void *src = NULL, *dst = NULL;
        int i;
 
-       memcpy_alloc_mem(&src, &dst, len);
+       memcpy_alloc_mem(&dst, &src, len);
 
        if (prefault)
                fn(dst, src, len);
index ff95a68741d1ccdb54e54d929f2292e88963a5d1..ac8721ffa6c8c681ccdb563607d5b80917062438 100644 (file)
@@ -21,6 +21,10 @@ ifeq ($(RAW_ARCH),x86_64)
   endif
 endif
 
+ifeq ($(RAW_ARCH),sparc64)
+  ARCH ?= sparc
+endif
+
 ARCH ?= $(RAW_ARCH)
 
 LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
index 42ac05aaf8ac1a8bf004c1e664aa10a1853111bc..b32ff3372514da7da33da49cfc2d52755f1db935 100644 (file)
@@ -49,7 +49,7 @@ test-hello.bin:
        $(BUILD)
 
 test-pthread-attr-setaffinity-np.bin:
-       $(BUILD) -Werror -lpthread
+       $(BUILD) -D_GNU_SOURCE -Werror -lpthread
 
 test-stackprotector-all.bin:
        $(BUILD) -Werror -fstack-protector-all
index 0a0d3ecb4e8af81b77222c29f92efcbf4485313b..2b81b72eca23726a03b263fb21efa649c13c9495 100644 (file)
@@ -5,10 +5,11 @@ int main(void)
 {
        int ret = 0;
        pthread_attr_t thread_attr;
+       cpu_set_t cs;
 
        pthread_attr_init(&thread_attr);
        /* don't care abt exact args, just the API itself in libpthread */
-       ret = pthread_attr_setaffinity_np(&thread_attr, 0, NULL);
+       ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cs), &cs);
 
        return ret;
 }
index 61bf9128e1f28ce40d3d694ef5d9de8bb9cda1f8..9d9db3b296dd6b50ed27e581c0d78aab65dfec49 100644 (file)
@@ -30,6 +30,8 @@ static int disasm_line__parse(char *line, char **namep, char **rawp);
 
 static void ins__delete(struct ins_operands *ops)
 {
+       if (ops == NULL)
+               return;
        zfree(&ops->source.raw);
        zfree(&ops->source.name);
        zfree(&ops->target.raw);
index 47b78b3f03257385023629696dda95e57d2b5ab7..6da965bdbc2caf8762b5018c6837422a00aac456 100644 (file)
@@ -25,6 +25,10 @@ static int perf_flag_probe(void)
        if (cpu < 0)
                cpu = 0;
 
+       /*
+        * Using -1 for the pid is a workaround to avoid gratuitous jump label
+        * changes.
+        */
        while (1) {
                /* check cloexec flag */
                fd = sys_perf_event_open(&attr, pid, cpu, -1,
@@ -47,16 +51,24 @@ static int perf_flag_probe(void)
                  err, strerror_r(err, sbuf, sizeof(sbuf)));
 
        /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-       fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
+       while (1) {
+               fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
+               if (fd < 0 && pid == -1 && errno == EACCES) {
+                       pid = 0;
+                       continue;
+               }
+               break;
+       }
        err = errno;
 
+       if (fd >= 0)
+               close(fd);
+
        if (WARN_ONCE(fd < 0 && err != EBUSY,
                      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
                      err, strerror_r(err, sbuf, sizeof(sbuf))))
                return -1;
 
-       close(fd);
-
        return 0;
 }
 
index c94a9e03ecf15744800d4a6bc68cca28ca70259e..e99a67632831a8e6548fae8a40b654f01b009d1e 100644 (file)
@@ -28,7 +28,7 @@ struct perf_mmap {
        int              mask;
        int              refcnt;
        unsigned int     prev;
-       char             event_copy[PERF_SAMPLE_MAX_SIZE];
+       char             event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
 };
 
 struct perf_evlist {
index b24f9d8727a894ccae13353abad0b951ec1b0916..33b7a2aef71322ab88b93e675c070bfc4a7c7da7 100644 (file)
 #include <symbol/kallsyms.h>
 #include "debug.h"
 
+#ifndef EM_AARCH64
+#define EM_AARCH64     183  /* ARM 64 bit */
+#endif
+
+
 #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
 extern char *cplus_demangle(const char *, int);
 
index 3ed7c0476d486d21dcb1c735478191ffa88c2fc7..2e2ba2efa0d9f97629ec5af9fb1136b3dee8962d 100644 (file)
@@ -209,7 +209,7 @@ $(OUTPUT)%.o: %.c
 
 $(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ)
        $(ECHO) "  CC      " $@
-       $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -Wl,-rpath=./ -lrt -lpci -L$(OUTPUT) -o $@
+       $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@
        $(QUIET) $(STRIPCMD) $@
 
 $(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC)
index 4e511221a0c11cd53588fc2ae507848ab94339cb..0db571340edbd94a7042a63f517f410b42c127d7 100644 (file)
@@ -22,6 +22,14 @@ TARGETS += vm
 TARGETS_HOTPLUG = cpu-hotplug
 TARGETS_HOTPLUG += memory-hotplug
 
+# Clear LDFLAGS and MAKEFLAGS if called from main
+# Makefile to avoid test build failures when test
+# Makefile doesn't have explicit build rules.
+ifeq (1,$(MAKELEVEL))
+undefine LDFLAGS
+override MAKEFLAGS =
+endif
+
 all:
        for TARGET in $(TARGETS); do \
                make -C $$TARGET; \
index e238c9559caf9a7757d2d389e0bda57cd73229a8..8d5d1d2ee7c1d793405685e8266045363bcce960 100644 (file)
@@ -30,7 +30,7 @@ static int execveat_(int fd, const char *path, char **argv, char **envp,
 #ifdef __NR_execveat
        return syscall(__NR_execveat, fd, path, argv, envp, flags);
 #else
-       errno = -ENOSYS;
+       errno = ENOSYS;
        return -1;
 #endif
 }
@@ -234,6 +234,14 @@ static int run_tests(void)
        int fd_cloexec = open_or_die("execveat", O_RDONLY|O_CLOEXEC);
        int fd_script_cloexec = open_or_die("script", O_RDONLY|O_CLOEXEC);
 
+       /* Check if we have execveat at all, and bail early if not */
+       errno = 0;
+       execveat_(-1, NULL, NULL, NULL, 0);
+       if (errno == ENOSYS) {
+               printf("[FAIL] ENOSYS calling execveat - no kernel support?\n");
+               return 1;
+       }
+
        /* Change file position to confirm it doesn't affect anything */
        lseek(fd, 10, SEEK_SET);
 
diff --git a/tools/thermal/tmon/.gitignore b/tools/thermal/tmon/.gitignore
new file mode 100644 (file)
index 0000000..06e96be
--- /dev/null
@@ -0,0 +1 @@
+/tmon
index e775adcbd29fdd3c0fccb66a09efc86e1fd95216..0788621c8d760f01f714d377a18c6a390a990fde 100644 (file)
@@ -2,8 +2,8 @@ VERSION = 1.0
 
 BINDIR=usr/bin
 WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
-CFLAGS= -O1 ${WARNFLAGS} -fstack-protector
-CC=gcc
+CFLAGS+= -O1 ${WARNFLAGS} -fstack-protector
+CC=$(CROSS_COMPILE)gcc
 
 CFLAGS+=-D VERSION=\"$(VERSION)\"
 LDFLAGS+=
@@ -16,12 +16,21 @@ INSTALL_CONFIGFILE=install -m 644 -p
 CONFIG_FILE=
 CONFIG_PATH=
 
+# Static builds might require -ltinfo, for instance
+ifneq ($(findstring -static, $(LDFLAGS)),)
+STATIC := --static
+endif
+
+TMON_LIBS=-lm -lpthread
+TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || \
+                    pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \
+                    echo -lpanel -lncurses)
 
 OBJS = tmon.o tui.o sysfs.o pid.o
 OBJS +=
 
 tmon: $(OBJS) Makefile tmon.h
-       $(CC) ${CFLAGS} $(LDFLAGS) $(OBJS)  -o $(TARGET) -lm -lpanel -lncursesw -ltinfo -lpthread
+       $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS)  -o $(TARGET) $(TMON_LIBS)
 
 valgrind: tmon
         sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET)  1> /dev/null
index 0be727cb9892ccc50e412a8a8cdb28f3f2476c68..02d5179803aae1cdfa43ecf23e25bc8e1c9b9e43 100644 (file)
@@ -55,6 +55,8 @@ The \fB-l --log\fP option write data to /var/tmp/tmon.log
 .PP
 The \fB-t --time-interval\fP option sets the polling interval in seconds
 .PP
+The \fB-T --target-temp\fP option sets the initial target temperature
+.PP
 The \fB-v --version\fP option shows the version of \fBtmon \fP
 .PP
 The \fB-z --zone\fP option sets the target therma zone instance to be controlled
index 09b7c3218334ba29dad1192d5dbd5a963dd51553..9aa19652e8e859a34a5db1edbae0c02170499967 100644 (file)
@@ -64,6 +64,7 @@ void usage()
        printf("  -h, --help            show this help message\n");
        printf("  -l, --log             log data to /var/tmp/tmon.log\n");
        printf("  -t, --time-interval   sampling time interval, > 1 sec.\n");
+       printf("  -T, --target-temp     initial target temperature\n");
        printf("  -v, --version         show version\n");
        printf("  -z, --zone            target thermal zone id\n");
 
@@ -219,6 +220,7 @@ static struct option opts[] = {
        { "control", 1, NULL, 'c' },
        { "daemon", 0, NULL, 'd' },
        { "time-interval", 1, NULL, 't' },
+       { "target-temp", 1, NULL, 'T' },
        { "log", 0, NULL, 'l' },
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'v' },
@@ -231,7 +233,7 @@ int main(int argc, char **argv)
 {
        int err = 0;
        int id2 = 0, c;
-       double yk = 0.0; /* controller output */
+       double yk = 0.0, temp; /* controller output */
        int target_tz_index;
 
        if (geteuid() != 0) {
@@ -239,7 +241,7 @@ int main(int argc, char **argv)
                exit(EXIT_FAILURE);
        }
 
-       while ((c = getopt_long(argc, argv, "c:dlht:vgz:", opts, &id2)) != -1) {
+       while ((c = getopt_long(argc, argv, "c:dlht:T:vgz:", opts, &id2)) != -1) {
                switch (c) {
                case 'c':
                        no_control = 0;
@@ -254,6 +256,14 @@ int main(int argc, char **argv)
                        if (ticktime < 1)
                                ticktime = 1;
                        break;
+               case 'T':
+                       temp = strtod(optarg, NULL);
+                       if (temp < 0) {
+                               fprintf(stderr, "error: temperature must be positive\n");
+                               return 1;
+                       }
+                       target_temp_user = temp;
+                       break;
                case 'l':
                        printf("Logging data to /var/tmp/tmon.log\n");
                        logging = 1;
index 89f8ef0e15c810936737a51f49f1a87f1f2c5648..b5d1c6b22dd3c8781c7cadd590f2121dfb8328cc 100644 (file)
 
 #include "tmon.h"
 
+#define min(x, y) ({                           \
+       typeof(x) _min1 = (x);                  \
+       typeof(y) _min2 = (y);                  \
+       (void) (&_min1 == &_min2);              \
+       _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({                           \
+       typeof(x) _max1 = (x);                  \
+       typeof(y) _max2 = (y);                  \
+       (void) (&_max1 == &_max2);              \
+       _max1 > _max2 ? _max1 : _max2; })
+
 static PANEL *data_panel;
 static PANEL *dialogue_panel;
 static PANEL *top;
@@ -98,6 +110,18 @@ void write_status_bar(int x, char *line)
        wrefresh(status_bar_window);
 }
 
+/* wrap at 5 */
+#define DIAG_DEV_ROWS  5
+/*
+ * list cooling devices + "set temp" entry; wraps after 5 rows, if they fit
+ */
+static int diag_dev_rows(void)
+{
+       int entries = ptdata.nr_cooling_dev + 1;
+       int rows = max(DIAG_DEV_ROWS, (entries + 1) / 2);
+       return min(rows, entries);
+}
+
 void setup_windows(void)
 {
        int y_begin = 1;
@@ -122,7 +146,7 @@ void setup_windows(void)
         * dialogue window is a pop-up, when needed it lays on top of cdev win
         */
 
-       dialogue_window = subwin(stdscr, ptdata.nr_cooling_dev+5, maxx-50,
+       dialogue_window = subwin(stdscr, diag_dev_rows() + 5, maxx-50,
                                DIAG_Y, DIAG_X);
 
        thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor *
@@ -258,21 +282,26 @@ void show_cooling_device(void)
 }
 
 const char DIAG_TITLE[] = "[ TUNABLES ]";
-#define DIAG_DEV_ROWS  5
 void show_dialogue(void)
 {
        int j, x = 0, y = 0;
+       int rows, cols;
        WINDOW *w = dialogue_window;
 
        if (tui_disabled || !w)
                return;
 
+       getmaxyx(w, rows, cols);
+
+       /* Silence compiler 'unused' warnings */
+       (void)cols;
+
        werase(w);
        box(w, 0, 0);
        mvwprintw(w, 0, maxx/4, DIAG_TITLE);
        /* list all the available tunables */
        for (j = 0; j <= ptdata.nr_cooling_dev; j++) {
-               y = j % DIAG_DEV_ROWS;
+               y = j % diag_dev_rows();
                if (y == 0 && j != 0)
                        x += 20;
                if (j == ptdata.nr_cooling_dev)
@@ -283,12 +312,10 @@ void show_dialogue(void)
                                ptdata.cdi[j].type, ptdata.cdi[j].instance);
        }
        wattron(w, A_BOLD);
-       mvwprintw(w, DIAG_DEV_ROWS+1, 1, "Enter Choice [A-Z]?");
+       mvwprintw(w, diag_dev_rows()+1, 1, "Enter Choice [A-Z]?");
        wattroff(w, A_BOLD);
-       /* y size of dialogue win is nr cdev + 5, so print legend
-        * at the bottom line
-        */
-       mvwprintw(w, ptdata.nr_cooling_dev+3, 1,
+       /* print legend at the bottom line */
+       mvwprintw(w, rows - 2, 1,
                "Legend: A=Active, P=Passive, C=Critical");
 
        wrefresh(dialogue_window);
@@ -437,7 +464,7 @@ static void handle_input_choice(int ch)
                        snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ",
                                ptdata.cdi[cdev_id].type,
                                ptdata.cdi[cdev_id].instance);
-               write_dialogue_win(buf, DIAG_DEV_ROWS+2, 2);
+               write_dialogue_win(buf, diag_dev_rows() + 2, 2);
                handle_input_val(cdev_id);
        } else {
                snprintf(buf, sizeof(buf), "Invalid selection %d", ch);
index a0a7b5d1a0703a00f81c9421856c0fdf1b1f6aaa..f9b9c7c5137214cb56bcc0cf7455d2d712dc6848 100644 (file)
@@ -72,6 +72,8 @@ static void vgic_v2_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
 {
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr |= (1ULL << lr);
+       else
+               vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr &= ~(1ULL << lr);
 }
 
 static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
@@ -84,6 +86,11 @@ static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr;
 }
 
+static void vgic_v2_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr = 0;
+}
+
 static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)
 {
        u32 misr = vcpu->arch.vgic_cpu.vgic_v2.vgic_misr;
@@ -148,6 +155,7 @@ static const struct vgic_ops vgic_v2_ops = {
        .sync_lr_elrsr          = vgic_v2_sync_lr_elrsr,
        .get_elrsr              = vgic_v2_get_elrsr,
        .get_eisr               = vgic_v2_get_eisr,
+       .clear_eisr             = vgic_v2_clear_eisr,
        .get_interrupt_status   = vgic_v2_get_interrupt_status,
        .enable_underflow       = vgic_v2_enable_underflow,
        .disable_underflow      = vgic_v2_disable_underflow,
index 3a62d8a9a2c6fce0cc2f94a6e558115785c03811..dff06021e74855a2d6cb9b8830fd30818a63c927 100644 (file)
@@ -104,6 +104,8 @@ static void vgic_v3_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
 {
        if (!(lr_desc.state & LR_STATE_MASK))
                vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
+       else
+               vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr &= ~(1U << lr);
 }
 
 static u64 vgic_v3_get_elrsr(const struct kvm_vcpu *vcpu)
@@ -116,6 +118,11 @@ static u64 vgic_v3_get_eisr(const struct kvm_vcpu *vcpu)
        return vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr;
 }
 
+static void vgic_v3_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr = 0;
+}
+
 static u32 vgic_v3_get_interrupt_status(const struct kvm_vcpu *vcpu)
 {
        u32 misr = vcpu->arch.vgic_cpu.vgic_v3.vgic_misr;
@@ -192,6 +199,7 @@ static const struct vgic_ops vgic_v3_ops = {
        .sync_lr_elrsr          = vgic_v3_sync_lr_elrsr,
        .get_elrsr              = vgic_v3_get_elrsr,
        .get_eisr               = vgic_v3_get_eisr,
+       .clear_eisr             = vgic_v3_clear_eisr,
        .get_interrupt_status   = vgic_v3_get_interrupt_status,
        .enable_underflow       = vgic_v3_enable_underflow,
        .disable_underflow      = vgic_v3_disable_underflow,
index 0cc6ab6005a07bb2e9453106a672e9efd4e237a6..c9f60f52458802f4a66a3912732d8665bc4a3e32 100644 (file)
@@ -883,6 +883,11 @@ static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
        return vgic_ops->get_eisr(vcpu);
 }
 
+static inline void vgic_clear_eisr(struct kvm_vcpu *vcpu)
+{
+       vgic_ops->clear_eisr(vcpu);
+}
+
 static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)
 {
        return vgic_ops->get_interrupt_status(vcpu);
@@ -922,6 +927,7 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
        vgic_set_lr(vcpu, lr_nr, vlr);
        clear_bit(lr_nr, vgic_cpu->lr_used);
        vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
+       vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
 }
 
 /*
@@ -978,6 +984,7 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                        BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
                        vlr.state |= LR_STATE_PENDING;
                        vgic_set_lr(vcpu, lr, vlr);
+                       vgic_sync_lr_elrsr(vcpu, lr, vlr);
                        return true;
                }
        }
@@ -999,6 +1006,7 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                vlr.state |= LR_EOI_INT;
 
        vgic_set_lr(vcpu, lr, vlr);
+       vgic_sync_lr_elrsr(vcpu, lr, vlr);
 
        return true;
 }
@@ -1136,6 +1144,14 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
        if (status & INT_STATUS_UNDERFLOW)
                vgic_disable_underflow(vcpu);
 
+       /*
+        * In the next iterations of the vcpu loop, if we sync the vgic state
+        * after flushing it, but before entering the guest (this happens for
+        * pending signals and vmid rollovers), then make sure we don't pick
+        * up any old maintenance interrupts here.
+        */
+       vgic_clear_eisr(vcpu);
+
        return level_pending;
 }
 
@@ -1583,8 +1599,10 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
         * emulation. So check this here again. KVM_CREATE_DEVICE does
         * the proper checks already.
         */
-       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2)
-               return -ENODEV;
+       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2) {
+               ret = -ENODEV;
+               goto out;
+       }
 
        /*
         * Any time a vcpu is run, vcpu_load is called which tries to grab the
index a1093700f3a41b84fc71591a7465940fdd4a017f..cc6a25d95fbff532bf5b00b0c339bec91ddc5bcf 100644 (file)
@@ -471,7 +471,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
        BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
 
        r = -ENOMEM;
-       kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+       kvm->memslots = kvm_kvzalloc(sizeof(struct kvm_memslots));
        if (!kvm->memslots)
                goto out_err_no_srcu;
 
@@ -522,7 +522,7 @@ out_err_no_srcu:
 out_err_no_disable:
        for (i = 0; i < KVM_NR_BUSES; i++)
                kfree(kvm->buses[i]);
-       kfree(kvm->memslots);
+       kvfree(kvm->memslots);
        kvm_arch_free_vm(kvm);
        return ERR_PTR(r);
 }
@@ -578,7 +578,7 @@ static void kvm_free_physmem(struct kvm *kvm)
        kvm_for_each_memslot(memslot, slots)
                kvm_free_physmem_slot(kvm, memslot, NULL);
 
-       kfree(kvm->memslots);
+       kvfree(kvm->memslots);
 }
 
 static void kvm_destroy_devices(struct kvm *kvm)
@@ -871,10 +871,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
                        goto out_free;
        }
 
-       slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots),
-                       GFP_KERNEL);
+       slots = kvm_kvzalloc(sizeof(struct kvm_memslots));
        if (!slots)
                goto out_free;
+       memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
 
        if ((change == KVM_MR_DELETE) || (change == KVM_MR_MOVE)) {
                slot = id_to_memslot(slots, mem->slot);
@@ -917,7 +917,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        kvm_arch_commit_memory_region(kvm, mem, &old, change);
 
        kvm_free_physmem_slot(kvm, &old, &new);
-       kfree(old_memslots);
+       kvfree(old_memslots);
 
        /*
         * IOMMU mapping:  New slots need to be mapped.  Old slots need to be
@@ -936,7 +936,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        return 0;
 
 out_slots:
-       kfree(slots);
+       kvfree(slots);
 out_free:
        kvm_free_physmem_slot(kvm, &new, &old);
 out:
@@ -2492,6 +2492,7 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
        case KVM_CAP_SIGNAL_MSI:
 #endif
 #ifdef CONFIG_HAVE_KVM_IRQFD
+       case KVM_CAP_IRQFD:
        case KVM_CAP_IRQFD_RESAMPLE:
 #endif
        case KVM_CAP_CHECK_EXTENSION_VM: